给一棵 N 个点的树,每个点有一个权值,求每个点的子树中有多少个点的权值比它大。
考虑线段树合并,将权值离散化,每个点开一棵权值线段树。
求答案时直接在权值线段树上查询,线段树合并时类似于可并堆。
要注意的是线段树要动态开点,合并时别忘了 up。
内存什么的最好算一下,数组别开小了。
1 #include<bits/stdc++.h> 2 #define rep(i,a,b) for(register int i=a;i<=b;++i) 3 #define rpd(i,a,b) for(register int i=a;i>=b;--i) 4 #define rep1(i,x) for(register int i=head[x];i;i=nxt[i]) 5 typedef long long ll; 6 const int N=2e5+5; 7 using namespace std; 8 inline int read(){ 9 int x=0,f=1;char ch=getchar(); 10 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 11 while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} 12 return x*f; 13 } 14 struct Tree{int x,l,r;}t[N<<4]; 15 int n,tot,cnt;int a[N],b[N],head[N],nxt[N],to[N],rt[N],ans[N]; 16 void add(int u,int v){nxt[++tot]=head[u];head[u]=tot;to[tot]=v;} 17 void up(int k){t[k].x=t[t[k].l].x+t[t[k].r].x;} 18 void build(int &k,int l,int r,int x){ 19 k=++cnt;if(l==r){t[k].x=1;return;} 20 int mid=l+r>>1; 21 if(mid>=x)build(t[k].l,l,mid,x); 22 else build(t[k].r,mid+1,r,x); 23 up(k); 24 } 25 int find(int k,int l,int r,int L,int R){ 26 if(L<=l&&r<=R)return t[k].x; 27 if(l>R||r<L)return 0; 28 int mid=l+r>>1; 29 return find(t[k].l,l,mid,L,R)+find(t[k].r,mid+1,r,L,R); 30 } 31 int merge(int x,int y){ 32 if(!x||!y)return x+y; 33 t[x].x+=t[y].x; 34 t[x].l=merge(t[x].l,t[y].l); 35 t[x].r=merge(t[x].r,t[y].r); 36 up(x); 37 return x; 38 } 39 void dfs(int x){ 40 rep1(i,x){ 41 int p=to[i];dfs(p); 42 rt[x]=merge(rt[x],rt[p]); 43 } 44 int k=lower_bound(b+1,b+n+1,a[x])-b; 45 ans[x]=find(rt[x],1,n,k+1,n); 46 } 47 int main(){ 48 n=read();rep(i,1,n)b[i]=a[i]=read(); 49 sort(b+1,b+n+1); 50 rep(i,1,n){ 51 int k=lower_bound(b+1,b+n+1,a[i])-b; 52 build(rt[i],1,n,k); 53 } 54 rep(i,2,n)add(read(),i);dfs(1); 55 rep(i,1,n)printf("%d\n",ans[i]); 56 return 0; 57 }