【USACO17JAN】Promotion Counting P
题目链接
如果只有一条链,可以直接离散化上权值树状数组一遍过。
在树上,考虑怎么消除不同子树之间的影响。
略微思考可以得出,可以在递归子树之前先求一遍询问前缀存下来,回溯回来再求一遍询问前缀,减一下得到子树新增的前缀。再用子树大小减一下,就是当前子树的答案。
代码(100分):
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<map> #include<set> #define IL inline #define RG register #define _1 first #define _2 second using namespace std; const int N=1e5; int n,p[N+3]; struct Edge{ int to,nxt; }e[N+3]; int top,h[N+3]; IL void gra_init(){ top=-1; memset(h,-1,sizeof h); } IL void link(int u,int v){ top++;; e[top].to=v; e[top].nxt=h[u]; h[u]=top; } int k,a[N+3]; IL int sol(int x){ int l=1,r=k,mid,ans; while(l<=r){ mid=(l+r)>>1; if(x<=a[mid]){ r=mid-1; ans=mid; } else l=mid+1; } return ans; } IL void discrete(){ memcpy(a,p,sizeof p); sort(a+1,a+n+1); k=1; for(int i=2;i<=n;i++) if(a[i]!=a[i-1]) a[++k]=a[i]; for(int i=1;i<=n;i++) p[i]=sol(p[i]); } int s[N+3]; IL int lowbit(int x){ return x&(-x); } IL void mdf(int p,int x){ for(;p<=k;p+=lowbit(p)) s[p]+=x; } IL int qry(int p){ int ret=0; for(;p;p-=lowbit(p)) ret+=s[p]; return ret; } int ans[N+3]; int dfs(int u){ int tmp=qry(p[u]),cnt=0; for(int i=h[u];~i;i=e[i].nxt) cnt+=dfs(e[i].to); cnt++; mdf(p[u],1); ans[u]=cnt-qry(p[u])+tmp; return cnt; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&p[i]); gra_init(); for(int i=2;i<=n;i++){ int x; scanf("%d",&x); link(x,i); } discrete(); memset(s,0,sizeof s); dfs(1); for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }