HDU-4366-(dfs序 树上线段树+区间最大值)

题目
肖恩拥有一家公司,他是老板。每一个员工有一个上司。每个员工都有忠诚和能力。有时肖恩会解雇一名员工。然后,一个被解雇的人的下属将取代他的能力比他高,并有最高的忠诚度的公司。西恩想知道谁来接替那个被解雇的人。

输入

在第一行中,数字T表示测试用例的数量。那么对于每一种情况,第一行包含2个数字n,m (2<=n,m<=50000),表示公司有n个人包括Sean,m是Sean的查询次数。员工编号从1到n-1,Sean的编号是0。按照n-1行,第i行(1<=i<=n-1)包含3个整数a,b,c(0<=a<=n-1,0<=b,c<=1000000),表示第i个员工的上级序列号,第i个员工的忠诚度和能力。每个员工的序列号都大于他的上级,每个员工都有不同的忠诚度。然后是m行查询。每行只有一个数字表明应该解雇谁的序列号。

输出

每个查询打印一个数字:谁将代替失去工作的人的序列号,如果没有人可以代替他,打印-1。

题解 :利用上司下属关系树得到dfs序。比如i。in[i]+1,out[i]-1这个区间内都是代表i的下属。

将能力从小到大排列。按照顺序插入的同时并查询。因为此时查询的话。查到的肯定是能力比自己高的。然后再查询[ in[i]+1,out[i]-1 ] 这个区间都是自己的下属。故就可以满足题目中的要求了。

查询返回的是 忠诚度数值。map搞一下。不知道重不重复。不管了反正A了。重复的话再搞一个线段树id[]数组。每次query的时候判断是下 id[pos]等于左右哪一个区间就行了。

还有 注意初始化。ans<=-1,这样不存在能力比他高的下属的话。返回的也是-1.

#include<bits/stdc++.h>
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
const int N=50010;
int tot,cnt;
int in[N],out[N],ans[N<<2],head[N],mmp[N];
struct Edge{int to,nex;}edge[N*1000];
void add(int from,int to){edge[++tot]=(Edge){to,head[from]};head[from]=tot;}
struct Person{
    int lo,ab,id;
    bool operator<(const Person& a)const{
        return ab>a.ab;
    }
}p[N];
bool cmp(Person a,Person b){return a.ab>b.ab;}
map<int,int>has;
void dfs(int x){
    in[x]=cnt++;
    for(int i=head[x];i!=-1;i=edge[i].nex) dfs(edge[i].to);
    out[x]=cnt;
}
void chanpoint(int index,int val,int l,int r,int pos){
    if(l==r){ans[pos]=val;return;}
    int mid=(l+r)>>1;
    if(index<=mid) chanpoint(index,val,l,mid,pos<<1);
    else chanpoint(index,val,mid+1,r,pos<<1|1);
    ans[pos]=max(ans[pos<<1],ans[pos<<1|1]);
}
int query(int cl,int cr,int l,int r,int pos){
    if(cl>cr) return -1;
    if(cl<=l&&r<=cr) return ans[pos];
    int mid=(l+r)>>1,ret=-1;
    if(cl<=mid) ret=max(ret,query(cl,cr,l,mid,pos<<1));
    if(cr>mid) ret=max(ret,query(cl,cr,mid+1,r,pos<<1|1));
    return ret;
}
int main(){
    int T,n,m;scanf("%d",&T);
    while(T--){
        tot=cnt=1;m(head,-1),m(ans,-1),has[-1]=-1;
        scanf("%d%d",&n,&m);
        for(int i=1,fa;i<n;i++){
            scanf("%d%d%d",&fa,&p[i].lo,&p[i].ab);
            add(fa,i),has[p[i].lo]=i,p[i].id=i;
        }
        dfs(0),--cnt;
        sort(p+1,p+n);
        for(int i=1,j;i<n;i=j){
            j=i;
            while(j<n&&p[j].ab==p[i].ab){//这个是为了应付能力相同的情况 应该查询完这些再插入
                int id=p[j].id;//保证每次询问时线段树里面的肯定是比自己能力低的
                int fin=query(in[id]+1,out[id]-1,1,cnt,1);
                mmp[id]=has[fin],++j;
            }
            j=i;
            while(j<n&&p[j].ab==p[i].ab) chanpoint(in[p[j].id],p[j].lo,1,cnt,1),++j;
        }
        int x;
        while(m--) scanf("%d",&x);printf("%d\n",mmp[x]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值