题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4756
线段树合并裸题。那种返回 int 的与传引用的 merge 都能过。不知别的题是不是这样。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+5,M=N*17*5; int n,m,a[N],tp[N],rt[N],hd[N],xnt,to[N],nxt[N],ans[N]; int tot,ls[M],rs[M],siz[M]; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return fx?ret:-ret; } void add(int x,int y) { to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt; } void merge(int &x,int y) { if(!x){x=y;return;} siz[x]+=siz[y]; if(ls[y])merge(ls[x],ls[y]); if(rs[y])merge(rs[x],rs[y]); } /* int merge(int x,int y) { if(!x||!y)return x+y; int d=++tot; siz[d]=siz[x]+siz[y]; ls[d]=merge(ls[x],ls[y]); rs[d]=merge(rs[x],rs[y]); return d; } */ int query(int l,int r,int cr,int L,int R) { if(!cr)return 0;if(l>=L&&r<=R)return siz[cr]; int mid=l+r>>1,ret=0; if(mid>=L)ret=query(l,mid,ls[cr],L,R); if(mid<R)ret+=query(mid+1,r,rs[cr],L,R); return ret; } void insert(int l,int r,int &cr,int p) { if(!cr)cr=++tot; siz[cr]++; if(l==r)return; int mid=l+r>>1; if(mid>=p) insert(l,mid,ls[cr],p); else insert(mid+1,r,rs[cr],p); } void dfs(int cr) { for(int i=hd[cr],v;i;i=nxt[i]) dfs(v=to[i]),/*rt[cr]=*/merge(rt[cr],rt[v]); ans[cr]=query(1,m,rt[cr],a[cr],m); insert(1,m,rt[cr],a[cr]); } int main() { n=rdn(); for(int i=1;i<=n;i++)a[i]=tp[i]=rdn(); sort(tp+1,tp+n+1); m=unique(tp+1,tp+n+1)-tp-1; for(int i=1;i<=n;i++)a[i]=lower_bound(tp+1,tp+n+1,a[i])-tp; for(int i=2,d;i<=n;i++) { d=rdn(); add(d,i); } dfs(1); for(int i=1;i<=n;i++)printf("%d ",ans[i]); return 0; }