CF600E Lomsat gelral(树上启发式合并)

Posted Keyzee

tags:

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

题目链接:https://codeforces.com/problemset/problem/600/E

这是一道树上启发式合并的题,就只是在模板的基础上稍微变化了一下

解题思路:我们需要计算当前u节点的答案,要计算加入非重链节点对此答案的影响,在计算加入节点对ans影响的时候,遍历u除了重链外的所有子树节点(因为重链部分的颜色已经被记录在了cnt内),当目前颜色数量(cnt[col[x]])大于记录的最大颜色数,就更新一下最大颜色数和sum颜色编号和,如果等于最大颜色数那么就让sum加等于这个颜色编号。

AC代码:

 #include<iostream>
 #include<algorithm>
 #include<cstring>
 #include<cmath>
 #include<vector>
 #include<set>
 #include<queue>
 #define int long long
 #define el "\\n"
 #define inf 0x3f3f3f3f
 using namespace std;
 using ll = long long;
 const int N = 100005;
 const int mod = 9901;
 
 int col[N];
 
 vector<int> G[N];
 
 int dfn[N], ctr[N], tot, siz[N], rnk[N], son[N];
 int cnt[N], sum, mx, ans[N];
 
 void add(int x) 
     cnt[col[x]] ++;
     if (cnt[col[x]] > mx) 
         mx = cnt[col[x]];
         sum = col[x];
     
     else if (cnt[col[x]] == mx) sum += col[x];
 
 
 void del(int x) 
     cnt[col[x]] --;
 
 
 int getans() 
     return sum;
 
 
 void dfs1(int u, int p) 
     dfn[u] = ++tot;
     siz[u] = 1;
     rnk[tot] = u;
     for (auto v :G[u]) 
         if (v != p) 
             dfs1(v, u);
             siz[u] += siz[v];
             if (siz[son[u]] < siz[v]) son[u] = v;
         
     
     ctr[u] = tot;
 
 
 void dfs2(int u, int p, bool keep) 
     for (auto v :G[u]) 
         if (v != p && v != son[u]) 
             dfs2(v, u, false);
         
     
     if (son[u]) dfs2(son[u], u, true);
     for (auto v :G[u]) 
         if (v != p && v != son[u]) 
             for (int i = dfn[v]; i <= ctr[v]; i++) 
                 add(rnk[i]);
             
         
     
     add(u);
     ans[u] = getans();
     if (!keep) 
         for (int i = dfn[u]; i <= ctr[u]; i++) 
             del(rnk[i]);
         
         sum = mx = 0;
     
 
 
 
 signed main() 
 
     ios::sync_with_stdio(false);
     cin.tie(0), cout.tie(0);
     int n;
     cin >> n;
     for (int i = 1; i <= n; i++) 
         cin >> col[i];
     
     for (int i = 1; i < n; i++) 
         int u, v;
         cin >> u >> v;
         G[u].push_back(v);
         G[v].push_back(u);
     
     dfs1(1, 0);
     dfs2(1, 0, 1);
     for (int i = 1; i <= n; i++) cout << ans[i] << " ";
 
     return 0;
 

 

 
 

CF600E Lomsat gelral(树上启发式合并)

LINK

Code:

#include <iostream>
#include <cstring>
#include <algorithm>
#define int long long
typedef long long LL;

using namespace std;
const int N = 1e5+10,M=2*N;
int n,m;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
    ne[idx]=h[a],e[idx]=b,h[a]=idx++;

int sz[N],son[N];
LL cnt[N],sum,mx;//记录当前节点为根子树的颜色数,最大颜色之和,最大颜色
LL ans[N];
int clr[N];
int dfs_son(int u,int fa)
    sz[u]=1;
    int pson=0;
    for(int i=h[u];~i;i=ne[i])
        int k=e[i];
        if(k==fa)continue;
        dfs_son(k,u);
        sz[u]+=sz[k];
        if(sz[k]>sz[pson])pson=k;
    
    son[u]=pson;
    return sz[u];

void calc(int u,int fa,int pson)//算所有轻儿子的贡献,不算u的重儿子子树
    cnt[clr[u]]++;
    if(cnt[clr[u]]>mx)mx=cnt[clr[u]],sum=clr[u];
    else if(cnt[clr[u]]==mx)sum+=clr[u];
    for(int i=h[u];~i;i=ne[i])
        int k=e[i];
        if(k==fa||k==pson)continue;
        calc(k,u,pson);
    

void remov(int u,int fa)//消除当前子树所有节点贡献
    int c=clr[u];
    cnt[c]--;
    for(int i=h[u];~i;i=ne[i])
        int k=e[i];
        if(k==fa)continue;
        remov(k,u);
    

void dfs(int u,int fa,int op)//op=1表示重儿子,0表示轻儿子
    for(int i=h[u];~i;i=ne[i])
        int k=e[i];
        if(k==fa||k==son[u])continue;//先跳过重儿子
        dfs(k,u,0);
    
    if(son[u])dfs(son[u],u,1);//最后遍历轻儿子
    calc(u,fa,son[u]);
    ans[u]=sum;
    if(!op)remov(u,fa),mx=sum=0;//记得清空

signed main()

    cin>>n;
    memset(h, -1, sizeof h);
    for(int i=1;i<=n;i++)cin>>clr[i];
    for(int i=1;i<n;i++)
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    
    dfs_son(1,-1);
    dfs(1,-1,1);
    for(int i=1;i<=n;i++)printf("%lld ",ans[i]);


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

cf600E Lomsat gelral

CF600E Lomsat gelral(线段树合并)

CF 600 E Lomsat gelral —— 树上启发式合并

cf600E. Lomsat gelral(树上启发式合并)

题解Lomsat gelral [CF600E]

「CF600E」Lomsat gelral