E. Lomsat gelral-CF600E-线段树合并

  • CF600E
  • 给你一棵有n个点的树,树上每个节点都有一种颜色ci。
  • 让你求每个点子树出现最多的颜色/编号的和
  • dfs遍历树过程进行线段树(权值线段树)合并,线段树无需按照*2 *2+1的方式去联系父子关系, 可以用一个id
  • 出现一个新的结点id++,这道题注意一下有多个数目相同的颜色时输出他们的和即可。线段树结点维护三个值,
  • 这个点的答案,最多的颜色数目,与颜色种类。
  • #include<bits/stdc++.h>
    using namespace std;
    #define maxn 123456
    #define ll long long
    #define lson tree[root].l
    #define rson tree[root].r
    int n,c[maxn],x,y,cnt,t;
    ll  id,ok[maxn];
    vector<int>gg[maxn];
    struct node
    {
        int l,r;
        ll big,sum,ans;
    } tree[4000050];
    void up(int root)
    {
        if(tree[lson].sum>tree[rson].sum)
        {
            tree[root].sum=tree[lson].sum;
            tree[root].big=tree[lson].big;
            tree[root].ans=tree[lson].ans;
        }
        else if(tree[lson].sum<tree[rson].sum)
        {
            tree[root].sum=tree[rson].sum;
            tree[root].big=tree[rson].big;
            tree[root].ans=tree[rson].ans;
        }
        else
        {
            tree[root].sum=tree[lson].sum;
            tree[root].big=tree[lson].big;
            tree[root].ans=tree[lson].ans+tree[rson].ans;
        }
    }
    int unon(int a,int b,int l,int r)
    {
        if(!a)return b;
        if(!b)return a;
        if(l==r)
        {
            tree[a].big=l;
            tree[a].sum+=tree[b].sum;
            tree[a].ans=l;
            return a;
        }
        int mid=(l+r)/2;
        tree[a].l=unon(tree[a].l,tree[b].l,l,mid);
        tree[a].r=unon(tree[a].r,tree[b].r,mid+1,r);
        up(a);
        return a;
    }
    void updata(int &root,int l,int r,int pos,int ad)
    {
        if(!root)root=++id;
        if(l==r)
        {
            tree[root].big=l;
            tree[root].sum+=ad;
            tree[root].ans=l;
            return ;
        }
        int mid=(l+r)/2;
        if(pos<=mid)updata(tree[root].l,l,mid,pos,ad);
        else updata(tree[root].r,mid+1,r,pos,ad);
        up(root);
    }
    void dfs(int cur,int fa)
    {
        for(int i=0; i<gg[cur].size(); i++)
        {
            int v=gg[cur][i];
            if(v==fa)continue;
            dfs(v,cur);
            unon(cur,v,1,100000);
        }
        updata(cur,1,100000,c[cur],1);
        ok[cur]=tree[cur].ans;
    }
    int main()
    {
        scanf("%d",&n);
        id=n;
        for(int i=1; i<=n; i++)
            scanf("%d",&c[i]);
        for(int i=1; i<n; i++)
        {
            scanf("%d%d",&x,&y);
            gg[x].push_back(y);
            gg[y].push_back(x);
        }
        dfs(1,0);
        for(int i=1; i<=n; i++)
        {
            printf("%lld",ok[i]);
            if(i<n)printf(" ");
            else printf("\n");
        }
        return 0;
    }
    

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值