Codeforces 700B Connecting Universities(树形DP)

【题目链接】 http://codeforces.com/problemset/problem/700/B

【题目大意】

  给出 一棵n个节点的树, 现在在这棵树上选取2*k个点,两两配对,使得其配对的两点间距离的和最大。

【题解】

  求出树的加权重心,那么答案就是每个点到加权重心的距离之和,但是实际上,并不需要求出加权重心,观察树边和其两边的询问节点,可以发现一个优美的性质,每条边对答案的贡献值为min(左边的点数,右边的点数),因此,树规计算每条边的贡献值,累加和就是答案。

【代码】

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N=200005;
int n,k,s[N],x,y;
long long ans=0;
vector<int> g[N];
void dfs(int x,int pre){
    for(int i=0;i<g[x].size();i++){
        if(g[x][i]==pre)continue;
        dfs(g[x][i],x);
        s[x]+=s[g[x][i]];
        ans+=min(s[g[x][i]],2*k-s[g[x][i]]);
    }
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=2*k;i++)scanf("%d",&x),s[x]++;
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        g[x].push_back(y);g[y].push_back(x);
    }dfs(1,-1);
    return printf("%I64d",ans),0;
}

  

时间: 2024-08-24 06:15:06

Codeforces 700B Connecting Universities(树形DP)的相关文章

Codeforces 700B Connecting Universities - 贪心

Treeland is a country in which there are n towns connected by n - 1 two-way road such that it's possible to get from any town to any other town. In Treeland there are 2k universities which are located in different towns. Recently, the president signe

codeforces 700B Connecting Universities

蛮有意思的....考虑每条边的贡献. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxv 200500 #define maxe 400500 using namespace std; int n,k,x,y,nume=0,g[maxv],size[maxv],fath[maxv]; long long ans=0; bool vis[m

codeforces 700B Connecting Universities 贪心dfs

分析:这个题一眼看上去很难,但是正着做不行,我们换个角度:考虑每条边的贡献 因为是一棵树,所以一条边把树分成两个集合,假如左边有x个学校,右边有y个学校 贪心地想,让每条边在学校的路径上最多,所以贡献为min(x,y) 具体实现:一次dfs即可,复杂度O(N) #include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #include <vector&

Codeforces 123E Maze(树形DP+期望)

[题目链接] http://codeforces.com/problemset/problem/123/E [题目大意] 给出一棵,给出从每个点出发的概率和以每个点为终点的概率,求出每次按照dfs序从起点到达终点的期望. [题解] 首先对于期望计算有X(x,y)=X(x)*X(y),所以对于每次dfs寻路只要求出其起点到终点的期望步数,乘上起点的概率和终点的概率即可.对于一个固定起点和终点的dfs寻路,我们可以发现如果一个点在必要路径上,那么这条路被走过的期望一定为1,如果不在必要路线上,那么走

bzoj 4424: Cf19E Fairy &amp;&amp; codeforces 19E. Fairy【树形dp】

参考:https://blog.csdn.net/heheda_is_an_oier/article/details/51131641 这个找奇偶环的dp1真是巧妙,感觉像tarjan一样 首先分情况讨论,如果没有奇环,每条边都可以删:如果有一个奇环,奇环上隋边山:否则,删被所有奇环覆盖且没被任何一个偶环覆盖的边 那么重点就是怎样找到所有的奇环和偶环 用树形dp来搞,设f[i]记录经过第i条边的奇环数,g[i]记录经过第i条边的偶环数,因为是边的编号而存的是双向边,所以dp的时候用i>>1表示

codeforces 455C C. Civilization(树形dp+树的直径+并查集)

题目链接: codeforces 455C 题目大意: 给出一些点,他们之间初始存在一些边,给出两种操作,第一种是查询某个点所在的树的直径,另一种是将两个树合并,要求使合并后的树的直径最小. 题目分析: 首先算取没做操作前的连通块里的树的直径,也就是先dfs一遍,找到深度最大的点,然后从这个点再搜,找到的最远的距离就是这棵树的直径,因为可以证明从根搜深度最大的点一定是树的直径的一个端点,因为它可以通过到达次大的深度的点或者找到与它公共祖先不在根处的获得树的直径. 然后每次合并,我们可以知道得到的

Codeforces 212E IT Restaurants 树形dp(水

题目链接:点击打开链接 题意: 给定n个点的树,染两种颜色,不同颜色不能相邻且要给尽可能多的节点染色.求颜色A和颜色B可能的染色节点个数.(copy from figo) 而且至少一个点染A,至少一个点染B dp[i][j]=1表示i点染j个A色是可行的 =0表示不可行. import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.math.Big

Educational Codeforces Round 52F(树形DP,vector)

#include<bits/stdc++.h>using namespace std;int n,k;vector<int>son[1000007];int dp[1000007],depth[1000007],ans[1000007];//dp[i]表示离i最近的叶子节点距离i的深度,depth[i]表示以i为根,回到i所能到达的叶子节点的数量,ans[i]表示以i为根,能到达的叶子节点数目最大,即题意所需void dfs(int now){    if(!son[now].si

CodeForces 158E Phone Talks 树形dp+计数

题目链接:点击打开链接 题意:给定n个点的树,常数d 给出每个点的权值,问有多少种划分方法使得划分后每个连通块里的最大权值-最小权值<=d 思路:点击打开链接 枚举每个点i 使得i是集合中的最小值. 则枚举时已经使得i是最小值,然后这个问题就变成单纯的划分问题了,上面链接里的题解已经很详尽了 import java.io.PrintWriter; import java.text.DecimalFormat; import java.util.ArrayDeque; import java.ut