• BZOJ4756


    Portal

    Description

    给出一个(n(nleq10^5))个点的带点权的以(1)为根的树,求每个点的子树中有多少个权值比该点大的点。

    Solution

    线段树合并。
    我们对于每一个点(u),建立一棵线段树保存子树(u)中的所有权值。那么(ans_u)就等于线段树中比(val_u)大的值有多少。而子树(u)中的所有权值等于(u)的所有子节点的子树中的权值加上(val_u),那么想要构建出(u)的线段树,只要将(son_u)的线段树全部合并起来再加上(val_u)就好啦。注意以上所说的线段树都是要动态开点的。
    如何合并两棵线段树呢?我们递归的去合并线段树中的每一个位置。merge(p1,p2)返回合并节点(p_1)(p_2)之后得到的节点,看代码就很容易理解啦。

    时间复杂度(O(nlogn))

    Code

    //[Usaco2017 Jan]Promotion Counting
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    inline char gc()
    {
        static char now[1<<16],*s,*t;
        if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
        return *s++;
    }
    inline int read()
    {
        int x=0; char ch=gc();
        while(ch<'0'||'9'<ch) ch=gc();
        while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
        return x;
    }
    const int N=1e5+10;
    int n,val[N]; int ans[N];
    int n0,map[N];
    void discrete()
    {
        for(int i=1;i<=n;i++) map[i]=val[i];
        sort(map+1,map+n+1); n0=unique(map+1,map+n+1)-map-1;
        for(int i=1;i<=n;i++) val[i]=lower_bound(map+1,map+n0+1,val[i])-map;
        n0++; //有可能会询问max+1
    }
    int cnt,h[N];
    struct edge{int v,nxt;} ed[N];
    void edAdd(int u,int v) {cnt++; ed[cnt].v=v,ed[cnt].nxt=h[u],h[u]=cnt;}
    const int Ns=3e6+10;
    int sgCnt,rt[N],ch[Ns][2],sum[Ns];
    void update(int p) {sum[p]=sum[ch[p][0]]+sum[ch[p][1]];}
    void ins(int &p,int L0,int R0,int x)
    {
        if(!p) p=++sgCnt;
        if(x<=L0&&R0<=x) {sum[p]++; return;}
        if(!p) p=++sgCnt;
        int mid=L0+R0>>1;
        if(x<=mid) ins(ch[p][0],L0,mid,x);
        else ins(ch[p][1],mid+1,R0,x);
        update(p);
    }
    int query(int &p,int L0,int R0,int L)
    {
        if(!p) p=++sgCnt;
        if(L<=L0) return sum[p];
        int mid=L0+R0>>1; int res=0;
        if(L<=mid) res+=query(ch[p][0],L0,mid,L);
        res+=query(ch[p][1],mid+1,R0,L);
        return res; 
    }
    int merge(int p1,int p2)
    {
        if(!p1||!p2) return !p1?p2:p1;
        ch[p1][0]=merge(ch[p1][0],ch[p2][0]);
        ch[p1][1]=merge(ch[p1][1],ch[p2][1]);
        sum[p1]+=sum[p2];
        return p1;
    }
    void dfs(int u)
    {
        ins(rt[u],1,n0,val[u]);
        for(int i=h[u];i;i=ed[i].nxt)
        {
            int v=ed[i].v;
            dfs(v); rt[u]=merge(rt[u],rt[v]);
        }
        ans[u]=query(rt[u],1,n0,val[u]+1);
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) val[i]=read();
        discrete();
        for(int i=2;i<=n;i++) edAdd(read(),i);
        dfs(1);
        for(int i=1;i<=n;i++) printf("%d
    ",ans[i]);
        return 0;
    } 
    

    P.S.

    Icefox的树状数组解法不知比我高到哪里去了
    太懒断更了几天...

  • 相关阅读:
    Mac 升级后 Git报错处理
    iOS 进制转换(十进制转62进制)
    转:基于IOS上MDM技术相关资料整理及汇总
    NPM ERR! 403 403 Forbidden 问题处理
    Rxjs学习,结合angular(搁置,后续还会添加)
    如何快速关联/修改Git远程仓库地址
    VUE 路由守卫 next() / next({ ...to, replace: true }) / next(‘/‘) 说明
    chrome developer tools 的一個 bug
    IBM MQ 2035错误
    tp5 gateway 报错 stream_socket_client(): unable to connect to tcp://127.0.0.1:1236 (Connection refused)
  • 原文地址:https://www.cnblogs.com/VisJiao/p/BZOJ4756.html
Copyright © 2020-2023  润新知