[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] 消防站的主要内容,如果未能解决你的问题,请参考以下文章