codeforces 1009F. Dominant Indices (dsu on tree)

题目链接

题意:

给定一棵以1位根的树,对于树上的每个节点求以该节点为根的子树中出现次数最多的深度,如果有多个则选择最小的那个

题解

  • 对这棵树以子树的节点个数大小进行轻重链剖分,每个节点最多经过$logn$个轻边即可到达根节点。
  • 对这棵树进行深度优先遍历,优先遍历轻边,再遍历重边并保留重边子树的信息,然后与轻边子树的信息合并统计答案。
  • 时间复杂度$O(nlogn)$,简单证明:每个节点只有在作为轻边子树的节点时会被重复遍历,而每个节点最多经过$logn$个轻边即可到达根节点。 所以每个节点最多被重复遍历$logn$次,因此时间复杂度为$nlogn$,实际上跑起来更快。
查看代码
#include <bits/stdc++.h>
using namespace std;
#define _for(i,a,b) for(int i = (a);i <= (b);++i)
typedef long long ll;
const int maxn = 1e6+5;
const int mod = 1e9+7;
ll qpow(ll a,ll b){ll res = 1;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}}
struct graph
{
    int head[maxn],nxt[maxn<<1],to[maxn<<1],w[maxn<<1],sz;
    void init(){memset(head,-1,sizeof(head));}
    graph(){init();}
    void push(int a,int b,int c){nxt[sz]=head[a],to[sz]=b,w[sz]=c,head[a]=sz++;}
    int& operator[](const int a){return to[a];}
}g;
int size[maxn],dp[maxn],dfn[maxn],son[maxn],num,ans[maxn],rnk[maxn],dep[maxn],cnt[maxn];
void dfs(int now,int pre)
{
    size[now]=1;
    dep[now]=dep[pre]+1;
    for(int i = g.head[now];~i;i = g.nxt[i]){
        if(pre==g[i])continue;
        dfs(g[i],now);
        size[now]+=size[g[i]];
        if(size[g[i]]>size[son[now]])son[now]=g[i];
    }
}
void dfs(int now,int pre,bool flag)
{
    dfn[++num]=now;
    rnk[now]=num;
    for(int i = g.head[now];~i;i = g.nxt[i]){
        if(g[i]!=pre&&g[i]!=son[now])dfs(g[i],now,0);
    }
    if(son[now])dfs(son[now],now,1);
    int nowans = ans[son[now]];
    int maxval = cnt[nowans];
    cnt[dep[now]]++;
    if(cnt[dep[now]]>maxval){
        maxval=cnt[dep[now]];
        nowans=dep[now];
    }
    else if(cnt[dep[now]]==maxval&&dep[now]<nowans){
        nowans=dep[now];
    }
    for(int i = g.head[now];~i;i = g.nxt[i]){
        if(g[i]==pre||g[i]==son[now])continue;
        for(int j = rnk[g[i]];j <= rnk[g[i]]+size[g[i]]-1;++j){
            int tmp = dep[dfn[j]];
            cnt[tmp]++;
            if(cnt[tmp]>maxval){
                maxval=cnt[tmp];
                nowans=tmp;
            }
            else if(cnt[tmp]==maxval&&tmp<nowans){
                nowans=tmp;
            }
        }
    }
    ans[now]=nowans;
    if(!flag){
        for(int i = rnk[now];i <= rnk[now]+size[now]-1;++i)cnt[dep[dfn[i]]]--;
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("simple.in","r",stdin);
    freopen("simple.out","w",stdout);
#endif
    int n;
    scanf("%d",&n);
    for(int i = 1,a,b;i < n;++i){
        scanf("%d%d",&a,&b);
        g.push(a,b,0);
        g.push(b,a,0);
    }
    dfs(1,0);
    dfs(1,0,1);
    for(int i = 1;i <= n;++i)printf("%d\n",ans[i]-dep[i]);
    return 0;
}
    </details>>
posted @ 2020-06-01 21:53  tryatry  阅读(177)  评论(0编辑  收藏  举报