【Codeforces 337D】Book of Evil 经典树形dp

题目链接:https://codeforces.ml/contest/337/problem/D

题目大意:

老题了关键在于转换.

给出一棵树与m个节点,询问有多少个点到这m个点的距离都小于等于p

题目思路:

经典做法:考虑每个点对答案的贡献

对于每个点来言,若与他距离最远的点的距离都小于等于p,那么他对答案的贡献就会+1

考虑树形dp的做法

类似求直径的做法,换根求最长链即可

s代表向下引申的最长链与次长链

t代表向上引申的最长链

这种题之前遇到过没有写博客导致思路还卡了一会儿,这次长记性先写下来

Code:

/*** keep hungry and calm CoolGuang!***/
#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=2e18;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll s[maxn][2],t[maxn];
int vis[maxn];
vector<int>v[maxn];
int f[maxn];
void dfs1(int u,int fa){
    if(vis[u]) s[u][0] = 0;
    f[u] = fa;
    for(int e:v[u]){
        if(e == fa) continue;
        dfs1(e,u);
        if(s[u][0]<s[e][0]+1){
            s[u][1] = s[u][0];
            s[u][0] = s[e][0]+1;
        }
        else if(s[u][1]<s[e][0]+1) s[u][1] = s[e][0]+1;
    }
}
void dfs2(int u,int fa){
    ll temp = -INF;
    if(vis[u]) t[u] = 0;
    if(u != fa){
        if(s[u][0]+1 == s[fa][0]) temp = s[fa][1];
        else temp = s[fa][0];
        t[u] = max(t[fa]+1,temp+1);
    }
    for(int e:v[u]){
        if(e == fa) continue;
        dfs2(e,u);
    }
}
int main()
{
    read(n);read(m);read(p);
    for(int i=1;i<=m;i++){
        ll x;read(x);
        vis[x] = 1;
    }
    for(int i=1;i<=n-1;i++){
        int x,y;scanf("%d%d",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    for(int i=1;i<=n;i++) s[i][0] = s[i][1] = t[i] = -INF;
    dfs1(1,1);
    dfs2(1,1);
    ll ans = 0;
    for(int i=1;i<=n;i++){
        ans += max(s[i][0],t[i])>p?0:1;
    }
    printf("%lld\n",ans);
    return 0;
}
/**
5 2 2
1 5
1 2
2 3
3 4
4 5
**/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/106996833