首页 > 代码库 > BZOJ 4756 [Usaco2017 Jan]Promotion Counting(线段树合并)

BZOJ 4756 [Usaco2017 Jan]Promotion Counting(线段树合并)

 

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=4756

 

【题目大意】

  给出一棵树,对于每个节点,求其子树中比父节点大的点个数

 

【题解】

  我们考虑每个权值建立一棵线段树,边dfs边将子节点合并为一颗线段树,
  那么只要查询当前点的树上后缀和即可。

 

【代码】

#include <cstdio>#include <algorithm>#include <cstring>#include <vector>using namespace std;const int N=100010,M=N*20;int n,a[N],ans[N],root[N],disc[N];vector<int> v[N];namespace Segment_Tree{    int tot;    struct node{int l,r,a,b,sum;}T[M];    void up(int x){T[x].sum=T[T[x].l].sum+T[T[x].r].sum;}    int build(int l,int r,int p){        int x=++tot;        T[x].a=l; T[x].b=r; T[x].sum=0;         if(l==r){T[x].sum=1;return x;}        int mid=(l+r)>>1;        if(p<=mid){T[x].l=build(l,mid,p);}        else{T[x].r=build(mid+1,r,p);}        return up(x),x;    }    int ask(int x,int l,int r){        if(!x)return 0;        if(l<=T[x].a&&T[x].b<=r)return T[x].sum;        int mid=(T[x].a+T[x].b)>>1,res=0;        if(l<=mid)res+=ask(T[x].l,l,r);        if(r>mid)res+=ask(T[x].r,l,r);        return res;    }    int merge(int x,int y){        if(!x||!y)return x^y;        T[x].l=merge(T[x].l,T[y].l);        T[x].r=merge(T[x].r,T[y].r);        return up(x),x;    }    void dfs(int x,int fx){        int res=0;        for(int i=0;i<v[x].size();i++){            int y=v[x][i];            if(y==fx)continue;            dfs(y,x);            res+=ask(root[y],a[x]+1,n);            root[x]=merge(root[x],root[y]);        }ans[x]=res;    }}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)scanf("%d",&a[i]),disc[i]=a[i];    sort(disc+1,disc+n+1);    int m=unique(disc+1,disc+n+1)-disc-1;    for(int i=1;i<=n;i++)a[i]=lower_bound(disc+1,disc+m+1,a[i])-disc;    for(int i=2;i<=n;i++){        int x; scanf("%d",&x);        v[x].push_back(i); v[i].push_back(x);    }    for(int i=1;i<=n;i++)root[i]=Segment_Tree::build(1,n,a[i]);    Segment_Tree::dfs(1,1);    for(int i=1;i<=n;i++)printf("%d\n",ans[i]);    return 0;}

BZOJ 4756 [Usaco2017 Jan]Promotion Counting(线段树合并)