Codeforces-1009F:Dominant Indices(树上启发式合并)

版权声明:http://blog.csdn.net/Mitsuha_。 https://blog.csdn.net/Mitsuha_/article/details/81987417

F. Dominant Indices
time limit per test4.5 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard output
You are given a rooted undirected tree consisting of n vertices. Vertex 1 is the root.

Let’s denote a depth array of vertex x as an infinite sequence [ d x , 0 , d x , 1 , d x , 2 , ] , where d x , i is the number of vertices y such that both conditions hold:

x is an ancestor of y;
the simple path from x to y traverses exactly i edges.

The dominant index of a depth array of vertex x (or, shortly, the dominant index of vertex x) is an index j such that:

for every k < j , d x , k < d x , j ;
for every k > j , d x , k d x , j
.
For every vertex in the tree calculate its dominant index.

Input
The first line contains one integer n ( 1 n 10 6 ) — the number of vertices in a tree.

Then n 1 lines follow, each containing two integers x and y ( 1 x , y n , x y ) . This line denotes an edge of the tree.

It is guaranteed that these edges form a tree.

Output
Output n numbers. i-th number should be equal to the dominant index of vertex i.

Examples
input
4
1 2
2 3
3 4
output
0
0
0
0
input
4
1 2
1 3
1 4
output
1
0
0
0
input
4
1 2
2 3
2 4
output
2
1
0
0

思路:树上启发式合并。记录每个节点的重儿子,对于一个节点,优先遍历轻儿子,最后遍历重儿子,保留重儿子信息,然后暴力查询轻儿子信息,合并到重儿子的信息上,然后更新答案。

扫描二维码关注公众号,回复: 2944381 查看本文章

最后,如果当前节点是重儿子,那就不清除当前信息;否则清除信息。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6+10;
typedef long long ll;
int siz[MAX],L[MAX],R[MAX],son[MAX],all=0;
int d[MAX];
vector<int>e[MAX];
void dfs(int k,int fa,int dep)//记录每个节点重儿子以及深度
{
    siz[k]=1;
    L[k]=++all;
    d[all]=dep;
    for(int i=0;i<e[k].size();i++)
    {
        int nex=e[k][i];
        if(nex==fa)continue;
        dfs(nex,k,dep+1);
        siz[k]+=siz[nex];
        if(siz[son[k]]<siz[nex])son[k]=nex;
    }
    R[k]=all;
}
int ans[MAX];
int cnt[MAX];   //cnt[i]记录深度为i的节点个数
int lenka=0;    //记录节点个数最多的深度
void cal(int k,int fa,int tp)
{
    for(int i=0;i<e[k].size();i++)//优先遍历轻儿子
    {
        int nex=e[k][i];
        if(nex==fa||nex==son[k])continue;
        cal(nex,k,0);
    }
    if(son[k])cal(son[k],k,1);    //最后遍历重儿子,此时重儿子的信息已被存入数组
    cnt[d[L[k]]]++;
    if(cnt[d[L[k]]]>cnt[lenka])lenka=d[L[k]];
    if(cnt[d[L[k]]]==cnt[lenka]&&lenka>d[L[k]])lenka=d[L[k]];
    for(int i=0;i<e[k].size();i++)//暴力将所有轻儿子的信息加入到cnt数组,并更新答案
    {
        int nex=e[k][i];
        if(nex==fa||nex==son[k])continue;
        for(int j=L[nex];j<=R[nex];j++)
        {
            cnt[d[j]]++;
            if(cnt[d[j]]>cnt[lenka])lenka=d[j];
            if(cnt[d[j]]==cnt[lenka]&&lenka>d[j])lenka=d[j];
        }
    }
    ans[k]=lenka-d[L[k]];
    if(tp==0)   //当前节点不是重儿子,清楚信息
    {
        lenka=0;
        for(int i=L[k];i<=R[k];i++)cnt[d[i]]--;
    }
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    all=0;
    dfs(1,0,0);
    lenka=0;
    cal(1,0,1);
    for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/81987417