codeforce337D -----简单树形DP

题目链接:http://codeforces.com/problemset/problem/337/D


解题思路:显然我们要找到这样的点,使得这个点到所有污染点的最远距离小于K,某个节点到污染点最远距离是由此节点到这个节点子树中的污染点的最远距离和父节点到兄弟子树中污染点的最远距离+1取最大值得到的。我们要保留一个此节点到子树中的最远距离dis[i],此节点向上走的最远距离updis[i],此节点到子树中距离最远的前两个Max[i][2],然后第一遍dfs处理dis数组和Max数组,第二遍统计一下就行了,下面上代码:


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int fa[N],dis[N],updis[N],head[N],Max[N][2];
int cnt,ans;
int n,m,k;
struct node
{
    int v,next;
}edge[2*N];
int addedge(int a,int b)
{
    edge[cnt].v = b;
    edge[cnt].next = head[a];
    head[a] = cnt++;
}
void dfs1(int u,int f)
{
    fa[u] = f;
    for(int i = head[u];i!=-1;i = edge[i].next)
    {
        int v = edge[i].v;
        if(v == fa[u])continue;
        dfs1(v,u);
        int tmp = dis[v] == -1?-1:dis[v]+1;
        if(tmp>Max[u][0])
        {
            dis[u] = tmp;
            Max[u][1] = Max[u][0];
            Max[u][0] = tmp;
        }
        else if(tmp>Max[u][1])
        {
            Max[u][1] = tmp;
        }
    }
}
void dfs2(int u)
{
    updis[u] = max(updis[u],updis[fa[u]] == -1?-1:updis[fa[u]]+1);
    int tmp = dis[u] == -1?-1:dis[u]+1;
    if(Max[fa[u]][0]!=tmp)
    {
        updis[u] = max(updis[u],Max[fa[u]][0] == -1?-1:Max[fa[u]][0]+1);
    }
    else
    {
        updis[u] = max(updis[u],Max[fa[u]][1] == -1?-1:Max[fa[u]][1]+1);
    }
    if(max(dis[u],updis[u])<=k)ans++;
    for(int i = head[u];i!=-1;i = edge[i].next)
    {
        int v = edge[i].v;
        if(v == fa[u])continue;
        dfs2(v);
    }
}
int main()
{
    int i,j,a,b;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        cnt = ans = 0;
        memset(head,-1,sizeof(head));
        memset(dis,-1,sizeof(dis));
        memset(updis,-1,sizeof(updis));
        memset(Max,-1,sizeof(Max));
        for(i = 1;i<=m;i++)
        {
            scanf("%d",&a);
            Max[a][0] = Max[a][1] = dis[a] = updis[a] = 0;
        }
        for(i = 1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            addedge(a,b);
            addedge(b,a);
        }
        fa[0] = fa[1] = 0;
        dfs1(1,0);
        dfs2(1);
        printf("%d\n",ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值