zoukankan      html  css  js  c++  java
  • 启发式合并

    Lomsat gelral

     CodeForces - 600E 

    题意:给你一个树,每个节点有一个颜色,求每个节点出现次数最大颜色编号和。

    考虑每个点都必然有多颗子树,统计该点的答案时必然要合并多个子树。
    启发式合并就是把小的往大的合并,这样保证log(n)的复杂度。
    这个题考虑这样做法:
    对于每一个点,
    1 . 统计出所有轻儿子的答案,不计入当前点的答案,
    2 . 统计重儿子的答案,计入当前点的答案,
    3 . 再回头扫一遍轻儿子,将轻儿子的答案和重儿子的答案合并,最终得到当前点的答案。
    这样合并保证了复杂度。
    但对于每一个轻儿子,当处理完之后,就要删除贡献,因为会对其他轻儿子产生影响。
    /*
    CF600E   
    启发式合并  复杂度 n*(log(n) 
    */
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int son[N],col[N],head[N],size[N];
    long long cnt[N],ans[N];
    struct edge{int v,next;}e[N<<2];
    int ecnt,n,maxc,thisson;
    long long thissum;
    void init(){
        memset(head,-1,sizeof head);
        memset(son,0,sizeof son);
        maxc=ecnt=thisson=thissum=0;
    }
    void add(int u,int v){
        e[ecnt].v=v;e[ecnt].next=head[u];head[u]=ecnt++;
    }
    void dfs_size(int u,int fa){//剖分树链
        size[u]=1;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].v;
            if(v==fa)continue;
            dfs_size(v,u);
            size[u]+=size[v];
            if(size[v]>size[son[u]])son[u]=v;
        }
    }
    void Count(int u,int fa,int val){//累积或删除贡献
        cnt[col[u]]+=val;
        if(cnt[col[u]]>maxc){
            maxc=cnt[col[u]];
            thissum=col[u];
        }
        else if(cnt[col[u]]==maxc)thissum+=col[u];
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].v;
            if(v==fa||v==thisson)continue;
            Count(v,u,val);
        }
    }
    void dfs_ans(int u,int fa,bool keep){//统计每个点的答案,保留或者不保留贡献
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].v;
            if(v==fa||v==son[u])continue;
            dfs_ans(v,u,false);
        }
        if(son[u]){
            dfs_ans(son[u],u,true);
            thisson=son[u];
        }
        Count(u,fa,1);
        thisson=0;
        ans[u]=thissum;
        if(!keep){
            Count(u,fa,-1);
            thissum=maxc=0;
        }
    }
    int main(){
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++)scanf("%d",&col[i]);
        for(int i=1,u,v;i<n;i++){
            scanf("%d %d",&u,&v);
            add(u,v);add(v,u);
        }
        dfs_size(1,-1);
        dfs_ans(1,-1,0);
        for(int i=1;i<=n;i++)printf("%I64d ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    (4)UIView和父子控件
    (2)第一个IOS程序
    svn本地目录结构for window
    (1)xcode基本设置和控制器等介绍
    git版本控制 for window安装和命令行使用
    linux虚拟机如何配置网卡信息(确保两台服务器通信)
    linux系统中firewalld防火墙管理工具firewallcmd(CLI命令行)
    linux系统中firewalld防火墙管理工具firewallconfig(GUI图形用户界面)
    linux系统中使用nmtui命令配置网络参数(图形用户界面)
    网卡是什么?
  • 原文地址:https://www.cnblogs.com/littlerita/p/12791208.html
Copyright © 2011-2022 走看看