cf 700 B Connecting Universities

题意:现在给以一棵$n$个结点的树,并给你$2k$个结点,现在要求你把这些节点互相配对,使得互相配对的节点之间的距离(路径上经过边的数目)之和最大。数据范围$1 \leq n \leq 200000, 2k \leq n$。

分析:贪心选择距离最大、次大...的结点对?貌似不对。暴力枚举所有可能?对但不可行。考虑节点对之间的距离实际上就是它们到LCA距离之和。因此单独考虑每个结点,它对答案的贡献实际上就是它到与其匹配节点的LCA的距离,这个距离必然不超过它到根的距离。如果我们有一种方法使得每个结点对答案的贡献都等于这个上界就好了,那么答案就是所有标记节点到根的距离之和。注意,要满足这个要求,与其匹配的结点应该和它不在根的同一个子树中,考虑根节点的各个子树中的标记节点,如果满足标记节点个数最多的子树不超过其余子树标记节点个数之和,那么是存在某种配对方法是得相互配对的节点分属不同子树的。即要求子树最大重量(含标记节点数目)不超过$k$即可(容易证明,讨论一下根是否是标记节点)。那么我们只需要对原图进行一次dfs找出这样的结点,并返回该节点作为根,再次dfs找出所有标记节点到根的距离之和即使答案。可以确定一定能够找到这样的根(提供一种证明思路,归纳法)。这样这道题可以在$O(n)$时间内解出。代码如下:

  1 #include <algorithm>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <string>
  5 #include <queue>
  6 #include <map>
  7 #include <set>
  8 #include <stack>
  9 #include <ctime>
 10 #include <cmath>
 11 #include <iostream>
 12 #include <assert.h>
 13 #pragma comment(linker, "/STACK:102400000,102400000")
 14 #define max(a, b) ((a) > (b) ? (a) : (b))
 15 #define min(a, b) ((a) < (b) ? (a) : (b))
 16 #define mp std :: make_pair
 17 #define st first
 18 #define nd second
 19 #define keyn (root->ch[1]->ch[0])
 20 #define lson (u << 1)
 21 #define rson (u << 1 | 1)
 22 #define pii std :: pair<int, int>
 23 #define pll pair<ll, ll>
 24 #define pb push_back
 25 #define type(x) __typeof(x.begin())
 26 #define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
 27 #define FOR(i, s, t) for(int i = (s); i <= (t); i++)
 28 #define ROF(i, t, s) for(int i = (t); i >= (s); i--)
 29 #define dbg(x) std::cout << x << std::endl
 30 #define dbg2(x, y) std::cout << x << " " << y << std::endl
 31 #define clr(x, i) memset(x, (i), sizeof(x))
 32 #define maximize(x, y) x = max((x), (y))
 33 #define minimize(x, y) x = min((x), (y))
 34 using namespace std;
 35 typedef long long ll;
 36 const int int_inf = 0x3f3f3f3f;
 37 const ll ll_inf = 0x3f3f3f3f3f3f3f3f;
 38 const int INT_INF = (int)((1ll << 31) - 1);
 39 const double double_inf = 1e30;
 40 const double eps = 1e-14;
 41 typedef unsigned long long ul;
 42 typedef unsigned int ui;
 43 inline int readint(){
 44     int x;
 45     scanf("%d", &x);
 46     return x;
 47 }
 48 inline int readstr(char *s){
 49     scanf("%s", s);
 50     return strlen(s);
 51 }
 52
 53 class cmpt{
 54 public:
 55     bool operator () (const int &x, const int &y) const{
 56         return x > y;
 57     }
 58 };
 59
 60 int Rand(int x, int o){
 61     //if o set, return [1, x], else return [0, x - 1]
 62     if(!x) return 0;
 63     int tem = (int)((double)rand() / RAND_MAX * x) % x;
 64     return o ? tem + 1 : tem;
 65 }
 66 ll ll_rand(ll x, int o){
 67     if(!x) return 0;
 68     ll tem = (ll)((double)rand() / RAND_MAX * x) % x;
 69     return o ? tem + 1 : tem;
 70 }
 71
 72 void data_gen(){
 73     srand(time(0));
 74     freopen("in.txt", "w", stdout);
 75     int kases = 40000;
 76     printf("%d\n", kases);
 77     while(kases--){
 78         ll sz = 1e18;
 79         printf("%lld\n", Rand(sz, 1));
 80     }
 81 }
 82
 83 struct cmpx{
 84     bool operator () (int x, int y) { return x > y; }
 85 };
 86 const int maxn = 2e5 + 10;
 87 int n, k;
 88 bool np[maxn];
 89 struct E{
 90     int to, nex;
 91 }e[maxn << 1];
 92 int head[maxn], N;
 93 void addE(int x, int y){
 94     e[N].nex = head[x];
 95     e[N].to = y;
 96     head[x] = N++;
 97     e[N].nex = head[y];
 98     e[N].to = x;
 99     head[y] = N++;
100 }
101 int cnt[maxn];
102 void dfs1(int u, int fa){
103     cnt[u] = np[u];
104     for(int i = head[u]; ~i; i = e[i].nex){
105         int v = e[i].to;
106         if(v == fa) continue;
107         dfs1(v, u);
108         cnt[u] += cnt[v];
109     }
110 }
111 int rt;
112 bool flag;
113 void dfs2(int u, int fa){
114     if(flag) return;
115     int maxi = 0;
116     int tot = 0;
117     for(int i = head[u]; ~i; i = e[i].nex){
118         int v = e[i].to;
119         if(v == fa) continue;
120         maximize(maxi, cnt[v]);
121         tot += cnt[v];
122     }
123     if(np[u]) ++tot;
124     maximize(maxi, 2 * k - tot);
125     if(maxi <= k){
126         rt = u;
127         flag = 1;
128         return;
129     }
130     for(int i = head[u]; ~i; i = e[i].nex) if(e[i].to != fa) dfs2(e[i].to, u);
131 }
132 ll dfs3(int u, int fa, int d){
133     ll tem = 0;
134     if(np[u]) tem += d;
135     for(int i = head[u]; ~i; i = e[i].nex){
136         int v = e[i].to;
137         if(v == fa) continue;
138         tem += dfs3(v, u, d + 1);
139     }
140     return tem;
141 }
142 int main(){
143     //data_gen(); return 0;
144     //C(); return 0;
145     int debug = 0;
146     if(debug) freopen("in.txt", "r", stdin);
147     //freopen("out.txt", "w", stdout);
148     while(~scanf("%d", &n)){
149         k = readint();
150         clr(np, 0);
151         FOR(i, 1, 2 * k) np[readint()] = 1;
152         N = 0, clr(head, -1);
153         FOR(i, 2, n){
154             int x = readint(), y = readint();
155             addE(x, y);
156         }
157         dfs1(1, -1);
158         rt = 1;
159         flag = 0;
160         dfs2(1, -1);
161         ll ans = dfs3(rt, -1, 0);
162         printf("%lld\n", ans);
163     }
164     return 0;
165 }

code:

时间: 2024-10-11 17:51:52

cf 700 B Connecting Universities的相关文章

B. Connecting Universities DFS,无向树

http://codeforces.com/problemset/problem/700/B 题意是,在一颗树中,有k个大学,要求两两匹配,他们之间的距离作为贡献,使得距离总和最大. 一开始的时候无从下手,一路在想某一个点应该和哪一个点去匹配.但是这样是错误的思路. 正解是观察边的贡献,如果某两个学校连接了,那么肯定有一条路径的,这条路径会经过很多的边,我们把经过某条边的次数统计出来.那么答案就是这棵树的边的权值和. 那怎么算一条边的贡献呢. 贪心地去想, 某一条边,把整颗树分成了两部分,那么第

cf701E 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(树形DP)

[题目链接] http://codeforces.com/problemset/problem/700/B [题目大意] 给出 一棵n个节点的树, 现在在这棵树上选取2*k个点,两两配对,使得其配对的两点间距离的和最大. [题解] 求出树的加权重心,那么答案就是每个点到加权重心的距离之和,但是实际上,并不需要求出加权重心,观察树边和其两边的询问节点,可以发现一个优美的性质,每条边对答案的贡献值为min(左边的点数,右边的点数),因此,树规计算每条边的贡献值,累加和就是答案. [代码] #incl

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 - 贪心

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

【CF700B】Connecting Universities(想法题,贪心,树上最短路)

题意:给出一棵树上的2*k个节点,给他们配对,使得他们之间的距离和最大. 思路:一条边的两侧如果有一侧没有给定的节点就不会被经过…… 如果有1个节点就会被经过1次…… 如果两侧分别有x,y个给定节点就会被经过min(x,y)次 因为要使总路程最大就是让每一条路被走过最多的次数 肯定是两侧各取一个 剩下的只能在某侧内部解决 所以按此统计即可 答案很大 用INT64 1 var head,vet,next,a,b,c,dep,flag,f:array[1..500000]of longint; 2

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 Round #364 (Div. 1)B. Connecting Universities

题目链接:传送门 题目大意:n个点构成一棵树,给定 k*2 点,要分成 k 组,使每组点之间的距离之和最大. 题目思路:因为是求距离之和最大,所以我们可以知道这样一个性质.如果以一条边为界,两边的子树均有给定的点,则这条边一定会经过 min(左边的给定点数,右边的给定点数)次. 那么这条边的贡献就是经过的次数. #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath>