用线段树合并水了这题。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100500 #define maxe 200500 using namespace std; int n,x,p[maxn],g[maxn],hash[maxn],nume=1,len=0,tot=0,ans[maxn]; int ls[maxn*20],rs[maxn*20],sum[maxn*20],root[maxn]; struct edge { int v,nxt; }e[maxe]; int read() { char ch;int f=1,data=0; while (ch<'0' || ch>'9') { if (ch=='-') f=-1; ch=getchar(); } while (ch>='0' && ch<='9') { data=data*10+ch-'0'; ch=getchar(); } return data*f; } void addedge(int u,int v) { e[++nume].v=v; e[nume].nxt=g[u]; g[u]=nume; } void pushup(int now) {sum[now]=sum[ls[now]]+sum[rs[now]];} void build(int &now,int left,int right,int pos) { now=++tot; if (left==right) {sum[now]=1;return;} int mid=(left+right)>>1; if (pos<=mid) build(ls[now],left,mid,pos); else build(rs[now],mid+1,right,pos); pushup(now); } int ask(int now,int left,int right,int l,int r) { if (!now) return 0; if ((left==l) && (right==r)) return sum[now]; int mid=(left+right)>>1; if (r<=mid) return ask(ls[now],left,mid,l,r); else if (l>=mid+1) return ask(rs[now],mid+1,right,l,r); else return ask(ls[now],left,mid,l,mid)+ask(rs[now],mid+1,right,mid+1,r); } int merge(int x,int y) { if (!x) return y; if (!y) return x; ls[x]=merge(ls[x],ls[y]);rs[x]=merge(rs[x],rs[y]); pushup(x); return x; } void dfs(int now,int fath) { int ret=0; for (int i=g[now];i;i=e[i].nxt) { int v=e[i].v; if (v==fath) continue; dfs(v,now); ret+=ask(root[v],1,n,p[now]+1,n); root[now]=merge(root[now],root[v]); } ans[now]=ret; } int main() { n=read(); for (int i=1;i<=n;i++) { p[i]=read(); hash[++len]=p[i]; } sort(hash+1,hash+len+1);len=unique(hash+1,hash+len+1)-hash-1; for (int i=1;i<=n;i++) p[i]=lower_bound(hash+1,hash+len+1,p[i])-hash; for (int i=2;i<=n;i++) { x=read(); addedge(i,x);addedge(x,i); } for (int i=1;i<=n;i++) build(root[i],1,n,p[i]); dfs(1,1); for (int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }