zoukankan      html  css  js  c++  java
  • 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
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    5个人的晚餐
    replace(),indexOf(),substring(),split(),join(),——各种小知识点
    2016-11-01——孤独留给自己,开心让给别人
    CMS3.0——初次邂逅express
    项目三(集团官网)——总结(2) 递归创建子目录
    项目三(集团官网)——总结(1) cookie
    jQuery_pager.js分页
    thinkjs——修改where默认条件为or
    优化之——查询数据库
    go net库
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj4756.html
Copyright © 2011-2022 走看看