启发式合并

Posted littlerita

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了启发式合并相关的知识,希望对你有一定的参考价值。

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

 

以上是关于启发式合并的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)

#线段树合并树上启发式合并#CF600E Lomsat gelral

BZOJ 2888 资源运输(启发式合并LCT)

luoguP5161 WD与数列 后缀自动机+线段树合并+启发式合并

数据结构 - 启发式合并

HDU6191 Query on A Tree (01字典树+启发式合并)