codeforces 337 D(樹的直徑性質)

題目鏈接:https://codeforces.com/problemset/problem/337/D

以下轉自:https://www.cnblogs.com/Khada-Jhin/p/10195287.html

DP求法:

DP求直徑的方法是對於每個點記錄這個點子樹中的最長鏈及與最長鏈處於不同子樹中的次長鏈,用每個點的最長鏈+次長鏈更新直徑,然後再將最長鏈上傳到父節點更新父節點的最長鏈或次長鏈。這種求法適用於所有求樹的直徑的情況。

性質:

1、直徑兩端點一定是兩個葉子節點

2、距離任意點最遠的點一定是直徑的一個端點,這個基於貪心求直徑方法的正確性可以得出

3、對於兩棵樹,如果第一棵樹直徑兩端點爲(u,v)(u,v),第二棵樹直徑兩端點爲(x,y)(x,y),用一條邊將兩棵樹連接,那麼新樹的直徑一定是u,v,x,y,u,v,x,y,中的兩個點

證明:如果新樹直徑不是原來兩棵樹中一棵的直徑,那麼新直徑一定經過兩棵樹的連接邊,新直徑在原來每棵樹中的部分一定是距離連接點最遠的點,即一定是原樹直徑的一個端點。

4、對於一棵樹,如果在一個點的上接一個葉子節點,那麼最多會改變直徑的一個端點

證明:假設在xx下面接一個點yy,直徑變成了(u,x)(u,x),原樹直徑爲(a,b)(a,b),那麼dis(u,x)>dis(a,b),dis(u,x)=dis(u,y)+1dis(u,x)>dis(a,b),dis(u,x)=dis(u,y)+1,即dis(u,y)+1>dis(a,b)dis(u,y)+1>dis(a,b),如果dis(u,y)<dis(a,b)dis(u,y)<dis(a,b),那麼顯然不成立;如果dis(u,y)=dis(a,b)dis(u,y)=dis(a,b),那麼(u,y)(u,y)也是原樹的直徑,符合上述結論。

5、若一棵樹存在多條直徑,那麼這些直徑交於一點且交點是這些直徑的中點

#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <bitset>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef vector<long long> VI;
typedef unsigned long long ull;
const ll inff = 0x3f3f3f3f3f3f3f3f;
#define FOR(i,a,b) for(int i(a);i<=(b);++i)
#define FOL(i,a,b) for(int i(a);i>=(b);--i)
#define SZ(x) ((long long)(x).size())
#define REW(a,b) memset(a,b,sizeof(a))
#define inf int(0x3f3f3f3f)
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define ss(a) scanf("%s",a)
#define mod ll(1e9+7)
#define pb push_back
#define eps 1e-6
#define lc d<<1
#define rc d<<1|1
#define Pll pair<ll,ll>
#define P pair<int,int>
#define pi acos(-1)
int n,m,dd,a[100008],x,y,pos,sd,sf,b[100008],ans;
vector<int>g[100008];
void dfs(int u,int fa,int d,int z)
{
    if(z&&d<=dd) b[u]++;
    if(a[u]&&d>sd) sd=d,pos=u;
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(v==fa) continue;
        dfs(v,u,d+1,z);
    }
}
void dfs1(int u,int fa,int d)
{
    if(a[u]&&d>sd) sd=d,sf=u;
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(v==fa) continue;
        dfs1(v,u,d+1);
    }
}
int main()
{
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m>>dd;
    FOR(i,1,m) si(x),a[x]=1;
    FOR(i,1,n-1)
    {
        si(x),si(y);
        g[x].pb(y);
        g[y].pb(x);
    }
    dfs(1,0,0,0);sf=pos,sd=0,dfs1(pos,0,0);
    dfs(pos,0,0,1),dfs(sf,0,0,1);
    FOR(i,1,n) if(b[i]>=2) ans++;
    cout<<ans<<endl;
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章