【BZOJ】1782: [Usaco2010 Feb]slowdown 慢慢游

【算法】DFS序+树状数组

【题解】题意相当于统计前i-1个点在第i个点的祖先的个数,显然可以用dfs维护,用树状数组差分维护前缀和。

出栈不新加节点就要注意左闭右开,即in[a[i]]处+1,ou[a[i]]+1处-1。

出栈新加节点就要注意数组开双倍

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=100010;
struct edge{int v,from;}e[maxn*3];
int first[maxn],in[maxn],ou[maxn],tot=0,cnt=0,b[maxn*2],a[maxn],n;

int read()
{
    char c;int s=0,t=1;
    while(!isdigit(c=getchar()))if(c=='-')t=-1;
    do{s=s*10+c-'0';}while(isdigit(c=getchar()));
    return s*t;
}
void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
void dfs(int x,int fa){
    in[x]=++cnt;
    for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa)dfs(e[i].v,x);
    ou[x]=++cnt;
}
void modify(int x,int k){for(int i=x;i<=cnt;i+=lowbit(i))b[i]+=k;}
int ask(int x){int ans=0;for(int i=x;i>=1;i-=lowbit(i))ans+=b[i];return ans;}
int main(){
    n=read();
    int u,v;
    for(int i=1;i<n;i++){
        u=read();v=read();
        insert(u,v);
        insert(v,u);
    }
    for(int i=1;i<=n;i++)a[i]=read();
    dfs(1,-1);
    for(int i=1;i<=n;i++){
        printf("%d\n",ask(in[a[i]]));
        modify(in[a[i]],1);
        modify(ou[a[i]],-1);
    }
    return 0;
}
View Code

 

posted @ 2017-08-31 10:20  ONION_CYC  阅读(273)  评论(0编辑  收藏  举报