[THOJ 1601] 消防站

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[THOJ 1601] 消防站相关的知识,希望对你有一定的参考价值。

题意

  给定一棵树.

  求一个点对, 最小化所有点到这个点对的距离的最大值.

  点到点对的距离被定义为点到点对的最小值.

  n <= 200000 .

 

分析

题解做法: 树的直径.

  找到树的直径, 取中点.

  左右各自再找到树的直径, 取中点 a, b, 用 a, b 计算答案.

我的做法: 二分答案 + 树形DP

  二分答案 dist , 判定是否存在一种方案, 使得所有点到点对的距离都 <= dist .

  我们选点的话, 一定要尽可能地靠近树根.

  考虑 DP , 记 Maxdep[x] 表示在以 x 为根的子树中, 没有被管辖的点到当前点的最大深度, d[x] 表示 x 对外管辖的能力.

  初始化  Maxdep[x] = 0, d[x] = -1 .

  转移   Maxdep[x] = max(Maxdep[son] + 1) , d[x] = max(d[son] + 1) .

  这时候的 Maxdep 可能是错的, 因为没有考虑到当前点的管辖能力(即某个子树中的点对中的点, 对另外一个子树的管辖) . 所以, 若 Maxdep[x] <= d[x] , 那么整个子树都可以被管辖, Maxdep[x] = -1 .

  这时候, 若 Maxdep[x] = dist , 那么就必须要管辖当前点了, 将当前点设立为点对中的一个点, Maxdep[x] = -1, d[x] = dist .

 

实现

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cctype>
 5 #include <algorithm>
 6 #include <vector>
 7 using namespace std;
 8 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
 9 inline int rd(void) {
10     int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
11     int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
12 }
13 inline void gmax(int &x, int y) { x = max(x, y); }
14 
15 const int N = 200005;
16 
17 int n, Maxdep[N], d[N], cnt;
18 vector<int> g[N];
19 
20 void DFS(int x, int par, int dis) {
21     Maxdep[x] = 0, d[x] = -1;
22     for (vector<int>::iterator it = g[x].begin(); it != g[x].end() && cnt <= 2; it++) if (*it != par) {
23         DFS(*it, x, dis);
24         gmax(Maxdep[x], Maxdep[*it] + 1);
25         gmax(d[x], d[*it] - 1);
26     }
27     if (Maxdep[x] == dis) Maxdep[x] = -1, d[x] = dis, cnt++;
28     else if (Maxdep[x] <= d[x]) Maxdep[x] = -1;
29 }
30 bool Judge(int dis) {
31     memset(Maxdep, 0, sizeof Maxdep), memset(d, -1, sizeof d), cnt = 0;
32     DFS(1, -1, dis);
33     return cnt + (Maxdep[1] > d[1]) <= 2;
34 }
35 
36 int main(void) {
37     #ifndef ONLINE_JUDGE
38         freopen("sta.in", "r", stdin);
39     #endif
40     
41     for (int nT = rd(), cas = 1; cas <= nT; cas++) {
42         F(i, 1, n) g[i].clear();
43         n = rd();
44         F(i, 1, n-1) {
45             int x = rd(), y = rd();
46             g[x].push_back(y), g[y].push_back(x);
47         }
48         
49         int L = 0, R = n;
50         while (L < R) {
51             int M = (L+R)>>1;
52             Judge(M) ? R = M : L = M+1;
53         }
54         printf("%d\n", L);
55     }
56     
57     return 0;
58 }

 

以上是关于[THOJ 1601] 消防站的主要内容,如果未能解决你的问题,请参考以下文章

[THOJ 1595] sup

[THOJ 1596] 旅行

[THOJ 1587] 小方格

[THOJ 1589] 椭球面 三分套三分

[THOJ 2471] lis 最值字典序

[THOJ 1599] dices 期望DP