hdu 4366 Successor dfs序 + 线段树
2015-11-10 16:38
423 查看
大致题意:题目给出一棵树,每个节点有能力值和忠诚度,查询u,就是查询在u的所有子树节点中找一个能力值比u高,(不能相同),而且忠诚度最大的结点。
思路:首先把树状的结构变成线性的,要不然不能利用题目里面的区间性,在子树中查询用到的就是dfs序,重新编号之后,把能力值从大到小排序,(注意一点,为了解决相同的能力值的冲突,在能力值相同的情况下,我是按照dfs序的从小到大排的),然后一个一个先查询,之后再插入。
http://acm.hdu.edu.cn/showproblem.php?pid=4366#include <map> #include <queue> #include <cmath> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN = 50005; const int MAXE = 100005; const int INF = 0x3f3f3f3f; struct Row_Edge{ int fa; int lo; int ab; int id; }RE[MAXN]; struct Edge { int to; Edge * next; }E[MAXE],*EE; struct Gragh{ int s; int e; int idx; Edge * first; }G[MAXN]; struct Node { int x,y; int value; int pos; }t[MAXN<<2]; int Q_Array[MAXN]; int ANS[MAXN]; int n,m; int index = 1; int pos[MAXN]; int maxlo,maxpos; void init() { //初始化; EE = E; memset(G,0,sizeof(G)); index = 1; } void addedge(int u,int v) { EE->to = v ; EE -> next = G[u].first; G[u].first = EE ++; EE->to = u ; EE -> next = G[v].first; G[v].first = EE ++; } void dfs(int u,int fa = 0) { //dfs序 //重新编号,找出一个点管辖的是那些点; //G[u]管辖的是从G[u].s 到 G[u].e 的点 pos[index] = u; G[u].idx = index; index ++; G[u].s = index; for(Edge * p = G[u].first ; p ; p = p -> next) { if(p->to != fa) { dfs(p->to,u); } } G[u].e = index - 1; } bool cmp(Row_Edge a1,Row_Edge a2) { if(a1.ab == a2.ab) { //相同的ab值是存在的,脑补出这种方法解决冲突。 return G[a1.id].idx < G[a2.id].idx; } return a1.ab > a2.ab; } void Push_Up(int rt) { if(t[rt<<1].value > t[rt<<1|1].value) { t[rt].pos = t[rt<<1].pos; } else { t[rt].pos = t[rt<<1|1].pos; } t[rt].value = max(t[rt<<1].value,t[rt<<1|1].value); } void Build(int x,int y,int rt) { t[rt].x = x ; t[rt].y = y; if(x == y) { t[rt].value = -1; t[rt].pos = pos[x]; return ; } int mid = (x + y) >> 1; Build(x,mid,rt<<1); Build(mid+1,y,rt<<1|1); Push_Up(rt); } void Update(int rt,int k,int value) { if(t[rt].x == t[rt].y) { t[rt].value = value; t[rt].pos = k; return ; } int mid = (t[rt].x + t[rt].y) >> 1; if(mid >= k) { Update(rt<<1,k,value); } else { Update(rt<<1|1,k,value); } Push_Up(rt); } void Query(int rt,int left,int right) { if(right < left) return ; if(left <= t[rt].x && right >= t[rt].y) { if(t[rt].value > maxlo) { maxlo = t[rt].value; maxpos = t[rt].pos; } return ; } int mid = (t[rt].x + t[rt].y) >> 1; if(mid >= left) { Query(rt<<1,left,right); } if(mid < right) { Query(rt<<1|1,left,right); } } void input() { init(); scanf("%d %d",&n,&m); for(int i = 1 ; i <= n - 1 ; i ++) { scanf("%d %d %d",&RE[i].fa,&RE[i].lo,&RE[i].ab); //存下边的原始条件,因为要排序从大到小一个一个插入; //RE[i].fa i结点的父亲 RE[i].lo i结点的荣誉值 RE[i].ab i结点的能力值; RE[i].id = i; addedge(i,RE[i].fa); //加边,形成一棵树; } for(int i = 1 ; i <= m ; i ++) { scanf("%d",&Q_Array[i]); //查询的序列; } } void solve() { Build(1,n,1); dfs(0); sort(RE+1,RE+n,cmp); // for(int i = 1 ; i <= n-1 ; i++) { // printf("%d %d %d\n",RE[i].id,RE[i].ab,RE[i].lo); // } //print(); //从大到小排序之后,插入n-1条边; for(int i = 1 ; i <= n - 1 ; i ++) { maxlo = -1; maxpos = -1; Query(1,G[RE[i].id].s,G[RE[i].id].e); //查询从开始到结束的区间,是否存在pos; ANS[RE[i].id] = maxpos; //根据ab值排序,所以应该根据lo的值插入; Update(1,G[RE[i].id].idx,RE[i].lo); } maxlo = -1; maxpos = -1; Query(1,1,n); ANS[0] = maxpos; for(int i = 1 ; i <= m ; i++) { if(ANS[Q_Array[i]] == -1) printf("%d\n",ANS[Q_Array[i]]); else printf("%d\n",pos[ANS[Q_Array[i]]]); } } int main(void) { freopen("a.in","r",stdin); int T; scanf("%d",&T); while(T--) { input(); solve(); } return 0; }
相关文章推荐
- java中的堆和栈
- git reflog
- C# ListView用法详解 很完整
- static静态变量的理解
- 自写任务调度模型
- RESTful in ruby on rails
- 04(maven+SSH)网上商城项目实战之maven热部署
- android发现之旅之媒体按键(耳机按键播放暂停键等)处理过程
- 处理JSON的Java API :JSON的简介
- Drawable转换为Bitmap两种方法
- EasyDarwin之hls
- cameraservice如何跨进程传递video数据——类图
- shader--流动水
- nyoj 士兵杀敌(四) 123 (线段树&&树状数组) 更新区间值求特定位置的值
- 从头开发技巧之自定义日志工具
- 小朋友报数-约瑟夫环
- android添加KeyMob广告管理库中文教程
- 判断年龄大小(函数递归)
- grunt 学习
- 定位-position