题目
肖恩拥有一家公司,他是老板。每一个员工有一个上司。每个员工都有忠诚和能力。有时肖恩会解雇一名员工。然后,一个被解雇的人的下属将取代他的能力比他高,并有最高的忠诚度的公司。西恩想知道谁来接替那个被解雇的人。
输入
在第一行中,数字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]);
}
}