Educational Codeforces Round 47 (Rated for Div. 2) -F Dominant Indices

洛谷传送门
Codeforces传送门

题意翻译

给出一棵有根树,对于每个节点 x x x,定义一个无穷序列 d d d,其中 d ( x , i ) d(x,i) d(x,i)表示以 x x x为根节点的子树中到 x x x的距离恰好为 i i i的点的个数, i = 0 ∼ ∞ i=0\sim \infin i=0,现在对每个点 x x x,希望求出一个值 j j j,使得对于任意 k &lt; j k&lt;j k<j d ( x , k ) &lt; d ( x , j ) d(x,k)&lt;d(x,j) d(x,k)<d(x,j),对于任意 k &gt; j , d ( x , k ) ≤ d ( x , j ) k&gt;j,d(x,k)\le d(x,j) k>j,d(x,k)d(x,j)

输入输出格式

输入格式:

第一行一个整数 n n n,表示树的节点个数 接下来 n − 1 n-1 n1行,每行两个整数, x x x y y y,表示 x , y x,y x,y之间有一条连边

输出格式:

n n n行,每行一个整数,第 i i i行表示 x = i x=i x=i时对应的 j j j

输入输出样例

输入样例#1:
4
1 2
2 3
3 4
输出样例#1:
0
0
0
0
输入样例#2:
4
1 2
1 3
1 4
输出样例#2:
1
0
0
0
输入样例#3:
4
1 2
2 3
2 4
输出样例#3:
2
1
0
0

解题分析

长链剖分模板题。没什么好说的…

注意转移重儿子的时候写假了还能过138个点…

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 1005000
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    for (; !isdigit(c); c = gc);
    for (;  isdigit(c); c = gc)
    x = (x << 1) + (x << 3) + c - 48;
}
int n, cnt;
struct Edge {int to, nex;} edge[MX << 1];
int buf[MX << 2], *dp[MX], *pt = buf;
int dep[MX], head[MX], son[MX], ans[MX];
IN void add(R int from, R int to)
{edge[++cnt] = {to, head[from]}, head[from] = cnt;}
void DFS(R int now, R int fa)
{
    for (R int i = head[now]; i; i = edge[i].nex)
    {
        if (edge[i].to == fa) continue;
        DFS(edge[i].to, now);
        if (dep[edge[i].to] > dep[son[now]]) son[now] = edge[i].to;
    }
    dep[now] = dep[son[now]] + 1;
}
IN void nw(R int now) {dp[now] = pt; pt += dep[now] + 2;}
void DP(R int now, R int fa)
{
    int mx = 0;
    dp[now][0] = 1;
    if (!son[now]) return;
    dp[son[now]] = dp[now] + 1;
    DP(son[now], now); ans[now] = ans[son[now]] + 1; mx = dp[now][ans[now]];
    for (R int i = head[now]; i; i = edge[i].nex)
    {
        if (edge[i].to == fa || edge[i].to == son[now]) continue;
        nw(edge[i].to);
        DP(edge[i].to, now);
        for (R int j = 0; j < dep[edge[i].to]; ++j)
        {
            dp[now][j + 1] += dp[edge[i].to][j];
            if (dp[now][j + 1] > mx) ans[now] = j + 1, mx = dp[now][j + 1];
            else if (dp[now][j + 1] == mx && ans[now] > j + 1) ans[now] = j + 1;
        }
    }
    if (dp[now][ans[now]] == 1) ans[now] = 0;
}
int main(void)
{
    in(n); int foo, bar;
    for (R int i = 1; i < n; ++i)
    in(foo), in(bar), add(foo, bar), add(bar, foo);
    DFS(1, 0); nw(1);
    DP(1, 0);
    for (R int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值