【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; }