hdu 4366

来源:互联网 发布:知乎禁止转载怎么复制 编辑:程序博客网 时间:2024/06/15 04:54

http://acm.hdu.edu.cn/showproblem.php?pid=4366

                     Successor

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 4340 Accepted Submission(s): 1100

Problem Description
Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has a loyalty and ability.Some times Sean will fire one staff.Then one of the fired man’s Subordinates will replace him whose ability is higher than him and has the highest loyalty for company.Sean want to know who will replace the fired man.

Input
In the first line a number T indicate the number of test cases. Then for each case the first line contain 2 numbers n,m (2<=n,m<=50000),indicate the company has n person include Sean ,m is the times of Sean’s query.Staffs are numbered from 1 to n-1,Sean’s number is 0.Follow n-1 lines,the i-th(1<=i<=n-1) line contains 3 integers a,b,c(0<=a<=n-1,0<=b,c<=1000000),indicate the i-th staff’s superior Serial number,i-th staff’s loyalty and ability.Every staff ‘s Serial number is bigger than his superior,Each staff has different loyalty.then follows m lines of queries.Each line only a number indicate the Serial number of whom should be fired.

Output
For every query print a number:the Serial number of whom would replace the losing job man,If there has no one to replace him,print -1.

Sample Input
1
3 2
0 100 99
1 101 100
1
2

Sample Output
2
-1

题目大意:
查询给定节点子树中,能力比给定节点大的忠诚度最大的节点;

思路:
(好题啊)
1,由于涉及到子树,那么需要dfs将树形结构转换成区间,这样就可以转换成线段树的区间了。可以使用对每个节点使用时间戳,标记进入的时间和出来的时间,那么,在这时间区间内的节点都将会是这个节点子树上的节点。
2,其次,要想使用线段树来做这道题,我们应该考虑该维护什么。通常维护都是些极值什么的,所以我们可以考虑维护最大的忠诚度。至于怎么保证能力大于给定的节点,那就可以通过控制节点的插入顺序来实现。将能力值较大的先插入,那么查询的时候,线段树中的节点能力值都将会是大于目前的那个节点值。
3,由于我们维护的是最大值,最后查询到的也将会是一个最大值,而不是题目要的编号,由于题中给出所有的忠诚度都是唯一的,所以可以使用map来保存忠诚度和编号之间的映射关系;

#include <cstdio>#include <algorithm>#include <cstring>#include <map>#include <vector>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn=50009;int ly[maxn<<2],In[maxn],Out[maxn],ans[maxn];//最大的忠诚度,节点进入和出来的时间戳int n,m,a,b,c,tot;vector<int> mp[maxn];map<int,int> mmp;struct node{    int loy,aby,id;} s[maxn];int cmp(node a,node b){    return a.aby>b.aby;}void dfs(int now){    In[now]=tot++;    for(int i=0; i<mp[now].size(); i++)        dfs(mp[now][i]);    Out[now]=tot;}void build(){    mmp.clear();    for(int i=0; i<=n; i++)        mp[i].clear();    memset(ans,-1,sizeof ans);    memset(In,0,sizeof In);    memset(Out,0,sizeof Out);    memset(ly,-1,sizeof ly);    tot=0;    mmp[-1]=-1;    int a;    for(int i=1; i<n; i++)    {        scanf("%d%d%d",&a,&s[i].loy,&s[i].aby);        s[i].id=i;        mmp[s[i].loy]=i;        mp[a].push_back(i);    }    dfs(0);    sort(s+1,s+n,cmp);}void update(int pos,int val,int l,int r,int rt){    if(l==r)    {        ly[rt]=val;        return;    }    int m=l+r>>1;    if(pos<=m) update(pos,val,lson);    else update(pos,val,rson);    ly[rt]=max(ly[rt<<1],ly[rt<<1|1]);}int query(int L,int R,int l,int r,int rt){    //此处很重要,在查询的过程有可能会出现这种情况    if(L>R) return -1;    if(L<=l&&r<=R)        return ly[rt];    int m=l+r>>1;    int tmp=-100000;    if(L<=m)        tmp=max(tmp,query(L,R,lson));    if(m<R)        tmp=max(tmp,query(L,R,rson));    return tmp;}int main(){    int t,tmp;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&m);        build();        for(int i=1,j; i<n; i=j)        //此循环控制插入的顺序,保证目前线段树中的节点忠诚度值大于当前查询节点        {            //先查询后插入            j=i;            while(j<n&&s[j].aby==s[i].aby)            {                int id=s[j].id;                //注意查询区间的范围                int tmp=query(In[id]+1,Out[id]-1,0,tot-1,1);                ans[id]=mmp[tmp];                j++;            }            j=i;            while(j<n&&s[j].aby==s[i].aby)            {                int id=s[j].id;                update(In[id],s[j].loy,0,tot-1,1);                j++;            }        }        while(m--)        {            scanf("%d",&tmp);            printf("%d\n",ans[tmp]);        }    }    return 0;}
原创粉丝点击