[AtCoder Grand Contest 009] D: Uninity (agc009D)

原题链接
https://agc009.contest.atcoder.jp/tasks/agc009_d

Description

给你一棵n个节点的树
你需要找到一种点分治方案,使得点分树的深度最小,输出这个最小深度(根的深度为0)
n<=100000

Solution

我们将每个点标号,表示这个点在点分树中的深度

有性质:两个标号相同的点之间的路径上一定有一个标号严格小于他们的标号的点

根据点分治的流程我们容易发现这是对的

方便起见,我们把标号反过来,叶子的标号为0,标号的最大值为这棵树深度
严格小于就变成了严格大于

Fi,j F i , j 表示从i的子树的节点到i的路径上还有多少个标号为j的没有被消掉(即路径上还没有标号严格大于它的点)

递归处理子树,然后将各个子树的加起来

如果一旦某一个标号出现了至少两次( Fi,j>1 F i , j > 1 ),那么意味着i这个节点的标号至少是j+1(否则就有一条路径全部确定,同时又不合法)

从最大的那个j+1向后找,直到第一个 F=0 F = 0 时(否则出现不合法),那么这个点就选这个标号,然后j小于这个标号的 Fi,j F i , j 都清空(这些路径已经合法了)

所以一遍DFS就搞定了

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 100005
using namespace std;
int nt[2*N],fs[N],dt[2*N],n,m,s[N],f[N][20],ans;
void link(int x,int y)
{
    nt[++m]=fs[x];
    dt[fs[x]=m]=y;
}
void dfs(int k,int fa)
{
    for(int i=fs[k];i;i=nt[i])
    {
        int p=dt[i];
        if(p!=fa)
        {
            dfs(p,k);
            fo(j,0,19) f[k][j]+=f[p][j];
        }
    }
    int lim=0;
    fod(j,19,0) if(f[k][j]>1)
    {
        lim=j+1;
        break;
    }
    while(f[k][lim]) lim++;
    s[k]=lim;
    fo(j,0,lim-1) f[k][j]=0;
    f[k][lim]++;
    ans=max(ans,s[k]);
}
int main()
{
    cin>>n;
    fo(i,1,n-1)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        link(x,y);
        link(y,x);
    }
    dfs(1,0);
    printf("%d",ans);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值