标签:https size mes turn 线段树 void using bzoj val
https://blog.csdn.net/keydou/article/details/83691189
bzoj 4756
题目大意:给出一棵树(根为 1),每个点有点权,对于每个点,询问它子树中点权比它大的点的个数
其实可以把这道题当成线段树合并入门题来做
首先把点权离散化,把所有的点都先单独建一颗权值线段树
然后从根开始 dfs ,一边 dfs 一边合并线段树,不断合并上去,最后求答案就行了
#include<cstdio> #include<cstring> #include<algorithm> #define N 100005 using namespace std; int n,m,t,tot; int first[N],v[N],nxt[N]; int a[N],ans[N],val[N],root[N],size[N*40],lc[N*40],rc[N*40]; void add(int x,int y) { t++; nxt[t]=first[x]; first[x]=t; v[t]=y; } void build(int &root,int l,int r,int val) { root=++tot; size[root]=1; if(l==r) return; int mid=(l+r)>>1; if(val<=mid) build(lc[root],l,mid,val); else build(rc[root],mid+1,r,val); } int Merge(int x,int y) { if(!x) return y; if(!y) return x; size[x]+=size[y]; lc[x]=Merge(lc[x],lc[y]); rc[x]=Merge(rc[x],rc[y]); return x; } int calc(int root,int l,int r,int x,int y) { if(l>=x&&r<=y) return size[root]; int ans=0,mid=(l+r)>>1; if(x<=mid) ans+=calc(lc[root],l,mid,x,y); if(y>mid) ans+=calc(rc[root],mid+1,r,x,y); return ans; } void dfs(int x) { int i,j; for(i=first[x];i;i=nxt[i]) { j=v[i],dfs(j); root[x]=Merge(root[x],root[j]); } ans[x]=calc(root[x],1,m,val[x]+1,m); } int main() { int x,i; scanf("%d",&n); for(i=1;i<=n;++i) scanf("%d",&a[i]),val[i]=a[i]; for(i=2;i<=n;++i) scanf("%d",&x),add(x,i); sort(a+1,a+n+1),m=unique(a+1,a+n+1)-(a+1); for(i=1;i<=n;++i) { val[i]=lower_bound(a+1,a+m+1,val[i])-a; build(root[i],1,m,val[i]); } dfs(1); for(i=1;i<=n;++i) printf("%d\n",ans[i]); return 0; }
标签:https size mes turn 线段树 void using bzoj val
原文地址:https://www.cnblogs.com/downrainsun/p/11421359.html