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);
}
原文地址:https://www.cnblogs.com/qywyt/p/9799954.html