题意:现在给以一棵$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