zoukankan      html  css  js  c++  java
  • P3605 [USACO17JAN]Promotion Counting P (线段树合并)

    前言

    线段树合并:https://www.luogu.com.cn/blog/styx-ferryman/xian-duan-shu-ge-bing-zong-ru-men-dao-fang-qi

    题目链接

    https://www.luogu.com.cn/problem/P3605

    题意

    给你一颗(n)个节点的树,每个节点都有权值且唯一,输出(n)行,输出的第(i)行应当给出有多少节点(i)的孩子比节点(i)权值大。

    思路

    有很多做法,这里用线段树合并来解决。注意,如果合并好的子节点没有利用价值了,那么(merge)那里可以直接合并到(a),否者要新建节点。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxx = 1e5+10;
    int a[maxx],b[maxx];
    int t[50*maxx],ls[50*maxx],rs[50*maxx],rt[maxx],cnt;
    int ans[maxx];
    int head[maxx],to[maxx],ne[maxx],tot;
    int mx;
    void add(int u,int v)
    {
        to[++tot]=v;ne[tot]=head[u];head[u]=tot;
    }
    void update(int &u,int l,int r,int x)
    {
        if(!u)u=++cnt;
        if(l==r)
        {
            t[u]++;
            return;
        }
        int mid=(l+r)/2;
        if(x<=mid)update(ls[u],l,mid,x);
        else update(rs[u],mid+1,r,x);
        t[u]=t[ls[u]]+t[rs[u]];
    }
    int query(int u,int l,int r,int p,int q)
    {
        if(!u)return 0;
        if(p<=l&&r<=q)return t[u];
        int mid=(l+r)/2;
        int ans=0;
        if(p<=mid)ans+=query(ls[u],l,mid,p,q);
        if(q>mid)ans+=query(rs[u],mid+1,r,p,q);
        return ans;
    }
    /*int merge(int a,int b,int l,int r)
    {
        if(!a)return b;
        if(!b)return a;
        int u=++cnt;
        if(l==r)
        {
            t[u]=t[a]+t[b];
            return u;
        }
        int mid=(l+r)/2;
        ls[u]=merge(ls[a],ls[b],l,mid);
        rs[u]=merge(rs[a],rs[b],mid+1,r);
        t[u]=t[ls[u]]+t[rs[u]];
        return u;
    }*/
    //因为我们是边合并边统计的,所以合并好的那些已经没有利用价值了,所以可以直接合并到a
    int merge(int a,int b,int l,int r)
    {
        if(!a)return b;
        if(!b)return a;
        if(l==r)
        {
            t[a]+=t[b];
            return a;
        }
        int mid=(l+r)/2;
        ls[a]=merge(ls[a],ls[b],l,mid);
        rs[a]=merge(rs[a],rs[b],mid+1,r);
        t[a]=t[ls[a]]+t[rs[a]];
        return a;
    }
    void dfs(int u)
    {
        for(int i=head[u];i;i=ne[i])
        {
            dfs(to[i]);
            rt[u]=merge(rt[u],rt[to[i]],1,mx);
        }
        ans[u]=query(rt[u],1,mx,min(a[u]+1,mx),mx);
        update(rt[u],1,mx,a[u]);
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),b[i]=a[i];
        int x;
        for(int i=2;i<=n;i++)
            scanf("%d",&x),add(x,i);
        sort(b+1,b+1+n);
        mx=unique(b+1,b+1+n)-b-1;
        for(int i=1;i<=n;i++)
            a[i]=lower_bound(b+1,b+1+mx,a[i])-b;
        dfs(1);
        for(int i=1;i<=n;i++)
            printf("%d
    ",ans[i]);
        return 0;
    }
    
    
  • 相关阅读:
    【Codeforces 923A】Primal Sport
    【Codeforces 924C】Riverside Curio
    【Codeforces 682C】Alyona and the Tree
    【Codeforces 1118D1】Coffee and Coursework (Easy version)
    【Codeforces 493C】Vasya and Basketball
    【Codeforces 598D】Igor In the Museum
    js 时间格式化
    C#自定义规则对比两个集合的对象是否相等
    VUE的组件DEMO
    js 去掉指定符号的字符串做法
  • 原文地址:https://www.cnblogs.com/HooYing/p/12961976.html
Copyright © 2011-2022 走看看