bzoj 4756 Promotion Counting —— 线段树合并
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4756
合并子树的权值线段树;
merge 返回 int 或者是 void 都可以。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define mid ((l+r)>>1) using namespace std; int const xn=1e5+5,xm=xn*20;// int n,p[xn],b[xn],hd[xn],ct,to[xn<<1],nxt[xn<<1]; int cnt,rt[xn],ls[xm],rs[xm],sum[xm],ans[xn],tot; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } int gt[20]; void wr(int x) { if(!x){puts("0"); return;} if(x<0)putchar('-'),x=-x; int t=0; while(x)gt[++t]=x%10,x/=10; for(int i=t;i;i--)putchar(gt[i]+'0'); puts(""); } void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;} void merge(int &x,int y) { if(!x){x=y; return;} sum[x]+=sum[y]; if(ls[y])merge(ls[x],ls[y]);//if if(rs[y])merge(rs[x],rs[y]);//if } /* int merge(int x,int y,int l,int r) { if(!x||!y)return x+y; sum[x]+=sum[y]; if(l==r)return x; ls[x]=merge(ls[x],ls[y],l,mid); rs[x]=merge(rs[x],rs[y],mid+1,r); return x; } */ void add(int &x,int l,int r,int pos) { if(!x)x=++cnt; sum[x]++; if(l==r)return; if(pos<=mid)add(ls[x],l,mid,pos); else add(rs[x],mid+1,r,pos); } int query(int x,int l,int r,int L,int R) { if(!x)return 0; if(l>=L&&r<=R)return sum[x]; int ret=0; if(mid>=L)ret+=query(ls[x],l,mid,L,R); if(mid<R)ret+=query(rs[x],mid+1,r,L,R); return ret; } void dfs(int x) { for(int i=hd[x],u;i;i=nxt[i]) { dfs(u=to[i]); // rt[x]=merge(rt[x],rt[u],1,tot); merge(rt[x],rt[u]); } ans[x]=query(rt[x],1,tot,p[x],tot); add(rt[x],1,tot,p[x]); } int main() { n=rd(); for(int i=1;i<=n;i++)p[i]=rd(),b[i]=p[i]; sort(b+1,b+n+1); tot=unique(b+1,b+n+1)-b-1; for(int i=1;i<=n;i++)p[i]=lower_bound(b+1,b+tot+1,p[i])-b; for(int i=2,fa;i<=n;i++)fa=rd(),add(fa,i); dfs(1); for(int i=1;i<=n;i++)wr(ans[i]); return 0; }