hdu 4366 Successor dfs序 + 线段树

来源:互联网 发布:linux下移动文件 编辑:程序博客网 时间:2024/05/21 19:27

大致题意:题目给出一棵树,每个节点有能力值和忠诚度,查询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;}
0 0