Codeforces 1029 E. Tree with Small Distances(树上dp)

题目直通车:http://codeforces.com/problemset/problem/1029/E

思路大意:在树上做dp,依次更新ar数组,ar[i]表示以i为根节点的子树对答案的最小贡献值,依次更新即可,具体细节见代码

/*
13
1 2
1 3
1 4
4 5
4 6
4 7
7 8
7 9
7 10
10 11
10 12
10 13

output:2
*/

#include<iostream>
#include<cstdio> 
#include<cmath>
#include<queue>
#include<vector>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<fstream>
#include<cstdlib>
#include<ctime>
#include<list>
#include<climits>
#include<bitset>
using namespace std;
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fopen freopen("input.in", "r", stdin);freopen("output.in", "w", stdout);
#define left asfdasdasdfasdfsdfasfsdfasfdas1
#define tan asfdasdasdfasdfasfdfasfsdfasfdas
typedef long long ll;
typedef unsigned int un;
const int desll[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
const ll mod=1e9;
const int maxn=2e5+7;
const int maxm=1e6+7;
const double eps=1e-4;
int m,n;
int ar[maxn];
vector<int> ve[maxn];
int dis[maxn],ans,arTwo[maxn];
int sum,maxx;
//arTwo[i]表示i节点与1相连时,以i为根的子树中需要与1相连的个数
//ar[i]表示以i为根节点的子树中需要与1相连的个数,即对答案的贡献值的最少值,dp更新ar即可
int func(int u,int pre,int num){
    int mid=0;
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(v==pre)continue;
        if(num==2)mid += func(v,u,num-1);
        else mid+=ar[v];
    }
    return min(mid, ar[u]);
}
void dfs2(int u,int pre){
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(v==pre)continue;
        dfs2(v,u);
    }
    arTwo[u] = func(u,pre,2);
    ar[u]=arTwo[u]+1;//u节点与1相连的情况
    int sumMid=0,maxMid=-n;
    for(int i=0;i<ve[u].size();i++){//u节点的一个子节点与1相连的情况
        int v=ve[u][i];
        if(v==pre)continue;
        sumMid += ar[v];
        maxMid = max(maxMid, ar[v]-arTwo[v]-1);
    }
    if(sumMid==0)sumMid=1,maxMid=0;//特判子节点的情况
    ar[u] = min(ar[u], sumMid-maxMid);
}
void funcDfs(int u,int pre,int num){
    if(num==0){
        int mid=0;
        for(int i=0;i<ve[u].size();i++){
            int v=ve[u][i];
            if(v==pre)continue;
            mid+=ar[v];
        }
        ans += min(ar[u], mid);
        return ;
    }
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(v==pre)continue;
        funcDfs(v,u,num-1);
    }
}

int main()
{
    scanf("%d",&n);
    fill(ar,ar+n+1,n);
    fill(arTwo,arTwo+n+1,n);
    for(int i=1;i<n;i++){
        int a,b;scanf("%d%d",&a,&b);
        ve[a].push_back(b);
        ve[b].push_back(a);
    }
    ans=0;
    dfs2(1,-1);
    funcDfs(1,0,2);
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/wa007/p/9566768.html