p1652
乱搞大法好!什么树的dfs序+线段树都是辣鸡.
这道题看似很难,但是它给了每个人的回房顺序,那么就好搞很多.
先存起来每个房间进入的时间和每个人进入的顺序,然后直接dfs.
根据dfs的性质当前一定只通过这个房间所在的一条路直接下来,那么只要求出这个过程中时间比自己小的就好,我们想到了再用一个高级数据结构存一下.这个过程相当于求前缀和了,可以上一个树状数组,比线段树好写无数倍.
总结一下:记录i房间进入时间t[i]和第i个人进入的房间num[i].dfs的时候now节点的答案ans[now]=sum(t[now]),然后再add(t[now],1),找节点中没走过的去dfs,完了之后再add(t[now],-1);
using namespace std; inline int lowbit(int x){ return x&(-x); } struct edge{ int x,y; int next; }e[1000010]; int head[100010],tot; int i,tx,ty; int n; int t[100010],v[100010],ans[100010],num[100010],c[100010]; inline void add(int x,int y){ tot++; e[tot].x=x; e[tot].y=y; e[tot].next=head[x]; head[x]=tot; return ; } inline void jia(int x){ for(;x<=n;x+=lowbit(x)) c[x]++; } inline void jian(int x){ for(;x<=n;x+=lowbit(x)) c[x]--; } inline int sum(int x){ int asd=0; for(;x;x-=lowbit(x)) asd+=c[x]; return asd; } inline void dfs(int now){ v[now]=1; ans[now]=sum(t[now]); jia(t[now]); for(int j=head[now];j;j=e[j].next) if(!v[e[j].y]) dfs(e[j].y); jian(t[now]); return ; } int main(){ n=read(); for(i=1;i<n;i++){ tx=read();ty=read(); add(tx,ty); add(ty,tx); } for(i=1;i<=n;i++){ num[i]=read(); t[num[i]]=i; } dfs(1); for(i=1;i<=n;i++) write(ans[num[i]]),putchar(10); }