首页 > 其他分享 >E. Lomsat gelral

E. Lomsat gelral

时间:2024-07-12 14:44:35浏览次数:10  
标签:ll next gelral sum 节点 now id Lomsat

原题链接

题解

暴力:遍历所有点为根节点的情况,然后遍历子节点,统计众数,时间复杂度 \(O(n^2)\)

优化:上面的算法时间复杂度之所以为 \(O(n^2)\) 是因为算父节点时,子节点又重新算了一遍,所以我们可以在算父节点时,保留一个子树的贡献,然后其他子树的贡献暴力遍历一遍
运用重链剖分,每次保留重儿子所在的子树的贡献,遍历轻儿子所在子树所有点的贡献,时间复杂度来到了 \(O(nlogn)\),

证明:

令轻儿子的“上边”为轻边,则每有一个轻边,都要遍历一遍其子树内的所有元素
所以节点 \(u\) 被暴力计算贡献的次数为根节点到 \(u\) 的路径上,轻边的个数
因为轻边所在子树大小小于父节点所在子树大小的一半,所以根节点到任意节点的路径上,轻边数量不超过 \(logn\)

code

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll dfn[100005];
ll sizes[100005];
vector<ll> G[100005];
ll bigson[100005];//代表编号
ll cnt=0;

ll haxi[1000005];

void dfs1(ll now,ll fa)
{
    dfn[now]=++cnt;
    haxi[cnt]=now;
    sizes[now]=1;
    ll maxs=0;

    for(auto next:G[now])
    {
        if(next==fa) continue;
        dfs1(next,now);
        sizes[now]+=sizes[next];
        if(sizes[next]>maxs)
        {
            bigson[now]=next;
            maxs=sizes[next];
        }
    }
}


ll tot=0;//出现不同颜色数
ll line=0;//最大出现次数
ll ans=0;//贡献
ll sum[100005]={0};//维护每个颜色出现的次数
ll st[100005]={0};//维护出现过的颜色的编号,算是离散化

void cancel()
{
    while(tot) sum[st[tot--]]=0;
    line=0;
    ans=0;
}

ll c[100005];
ll res[1000005];

void add(ll id)
{
    if(!sum[c[id]]) st[++tot]=c[id];

    sum[c[id]]++;
    if(sum[c[id]]>line)
    {
        ans=c[id];
        line=sum[c[id]];
    }
    else if(sum[c[id]]==line) ans+=c[id];//由于颜色出现统计只有清零和增加两种,所以ans要么变大要么为零
}

void dfs2(ll now)
{
    for(auto next:G[now])
    {
        if(dfn[next]<dfn[now]||next==bigson[now]) continue;

        dfs2(next);
        cancel();//取消其贡献。为什么要取消?为了清空计算其他子树
    }

    if(bigson[now])
    {
        dfs2(bigson[now]);
    }


    for(auto next:G[now])
    {
        if(dfn[next]<dfn[now]||next==bigson[now]) continue;

        for(ll i=dfn[next];i<=dfn[next]+sizes[next]-1;i++)
        {
            add(haxi[i]);//加上其贡献
        }
    }

    add(now);
    res[now]=ans;
}

void solve()
{
    ll n;
    cin>>n;

    for(ll i=1;i<=n;i++) cin>>c[i];

    for(ll i=1;i<n;i++)
    {
        ll x,y;
        cin>>x>>y;

        G[x].push_back(y);
        G[y].push_back(x);
    }

    dfs1(1,1);
    dfs2(1);

    for(ll i=1;i<=n;i++) cout<<res[i]<<' ';
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    ll t=1;
    //cin>>t;
    while(t--) solve();
    return 0;
}

标签:ll,next,gelral,sum,节点,now,id,Lomsat
From: https://www.cnblogs.com/pure4knowledge/p/18298308

相关文章

  • E. Lomsat gelral
    https://codeforces.com/contest/600/problem/E题意:给一颗树,如果当前叶子为根的树中数字出现最多次数为k,求该树中所有出现次数为k的数字之和。思路:dfs+线段树合并。总结:第一次接触线段树合并,整理了3个上午才整理出模板来,不知道这种线段树合并有没有区间更新的功能,这个题目是......
  • CF600E Lomsat gelral
    题意给定一棵根为\(1\)的有根树。每个节点有颜色,求每个节点子树内出现最多的颜色编号之和。SolDsuontree板子题。首先对于整棵树进行轻重链剖分,注意到一个关键性质:轻边只有\(log\)条。\(n^2\)的暴力是\(trivial\)的,不再赘述。注意到中间有很多节点被重复计算了......
  • CF600E Lomsat gelral
    树上启发式合并(dsuontree)通常用来查询不带修的子树信息,信息要求可合并。对于一个结点\(u\),其步骤如下:求解其轻儿子的答案,同时清除递归产生的影响。求解其重儿子的答案,保留递归产生的影响。将轻儿子子树内的每个结点都合并进答案中,同时成为以\(u\)为根的子树产生的影响。......
  • CF600E Lomsat gelral(树上启发式合并)
    题目链接:https://codeforces.com/problemset/problem/600/E这是一道树上启发式合并的题,就只是在模板的基础上稍微变化了一下解题思路:我们需要计算当前u节点的答案,要计算加入非重链节点对此答案的影响,在计算加入节点对ans影响的时候,遍历u除了重链外的所有子树节点(因为重链部分的......
  • Educational Codeforces Round 2 E Lomsat gelral 线段树合并
    题目链接大致题意给你一棵有n个点的树,树上每个节点都有一种颜色ci(ci≤n),让你求每个点子树出现最多的颜色/编号的和记性不好,主要是为了防止自己忘掉,今天和队友合作写题......
  • Lomsat gelral
    Lomsatgelral统计节点出现次数最多的颜色之和概要:运用树链剖分,每次不用重新跑重儿子,从而将复杂度降低到nlogn#include<bits/stdc++.h>usingnamespacestd;usingl......