BZOJ1776 - [Usaco2010 Hol]cowpol 奶牛政坛
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1776
题目大意:一棵n个点的树,树上每个点属于一个党派,要求每个党派的最远距离点。两点间距离为两点间边的个数。
主观思路:看到树上两点距离立即想到dep[x] + dep[y] - 2 * dep[lca(x, y)]这件事。于是想到树形序列化的思想,搞成一个中序遍历的dfs序列。序列中每个点有一个dep,也有一个col表示点深度和所属党派,依次枚举dfs序列中的点,对于当前点x它与之前所有同党派y之间的最远距离取决于dep[y] - 2 * min{dep[k], k在dfs序列y,x之间}。这里用了一种类似单调队列的思想可以做到每个点只进队(我对每个党派的点开了一个vector)一次,详见代码,属于乱搞。对于那个min就用rmq提前对dep维护一下即可。
1 /************************************************************** 2 Problem: 1776 3 User: SWUN2015 4 Language: C++ 5 Result: Accepted 6 Time:1988 ms 7 Memory:48060 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstdlib> 12 #include <cstring> 13 #include <cmath> 14 #include <vector> 15 #include <algorithm> 16 using namespace std; 17 18 const int MaxN = 2 * 1e5, MaxM = 4 * 1e5; 19 struct ARR 20 { 21 int loc, dep, MiN, pre; 22 }; 23 int n, K, all, Root, tot; 24 int dep[MaxN + 5], col[MaxN + 5], dfs_seq[MaxN + 5], ans[MaxN + 5]; 25 int p[MaxN + 5], pre[MaxM + 5], last[MaxN + 5], other[MaxM + 5]; 26 int rmq[MaxN + 5][30]; 27 vector <ARR> a[MaxN + 5]; 28 29 void Build(int x, int y) 30 { 31 pre[++all] = last[x]; 32 last[x] = all; 33 other[all] = y; 34 } 35 36 void Init() 37 { 38 all = -1; memset(last, -1, sizeof(last)); 39 scanf("%d%d", &n, &K); 40 for (int i = 1; i <= n; i++) 41 { 42 scanf("%d%d", &col[i], &p[i]); 43 Build(i, p[i]); Build(p[i], i); 44 if (p[i] == 0) Root = i; 45 } 46 } 47 48 void Dfs(int x, int fa, int d) 49 { 50 dfs_seq[++tot] = x; 51 dep[x] = d; 52 int ed = last[x], dr; 53 while (ed != -1) 54 { 55 dr = other[ed]; 56 if (dr != fa) Dfs(dr, x, d + 1); 57 ed = pre[ed]; 58 } 59 } 60 61 void RMQ() 62 { 63 int K = (int)(double(log(n)) / double(log(2))); 64 for (int i = 1; i <= n; i++) rmq[i][0] = dep[dfs_seq[i]]; 65 for (int i = 1; i <= K; i++) 66 for (int j = 1; j <= n - (1 << i) + 1; j++) 67 rmq[j][i] = min(rmq[j][i - 1], rmq[j + (1 << (i - 1))][i - 1]); 68 } 69 70 void Insert(int x) 71 { 72 int t, c = col[dfs_seq[x]]; 73 if (a[c].size() > 0) 74 { 75 t = a[c].size(); 76 int pos, dd = 0; 77 int l = a[c][--t].loc + 1, r = x; 78 int K = (int)(double(log(r - l + 1)) / double(log(2))); 79 int MiN = min(rmq[l][K], rmq[r - (1 << K) + 1][K]); 80 ARR res; 81 while (t >= 0 && MiN <= a[c][t].MiN) 82 { 83 if (a[c][t].dep >= dd) dd = a[c][t].dep, pos = a[c][t].loc; 84 a[c].pop_back(); t--; 85 } 86 res.dep = dd; res.loc = pos; res.MiN = MiN; 87 if (t >= 0) res.pre = max(a[c][t].pre, res.dep - 2 * (res.MiN - 1)); 88 else res.pre = res.dep - 2 * (res.MiN - 1); 89 a[c].push_back(res); 90 res.dep = dep[dfs_seq[x]]; res.loc = x; res.MiN = 1 << 30; 91 res.pre = a[c][t + 1].pre; 92 a[c].push_back(res); 93 t += 2; 94 ans[c] = max(ans[c], a[c][t].pre + dep[dfs_seq[x]]); 95 } 96 else 97 { 98 t = 0; 99 ARR res; 100 res.dep = dep[dfs_seq[x]]; res.loc = x; res.MiN = 1 << 30; res.pre = -(1 << 30); 101 a[c].push_back(res); 102 } 103 } 104 105 void Solve() 106 { 107 Dfs(Root, 0, 0); RMQ(); 108 for (int i = 1; i <= n; i++) {Insert(i);}//printf("%d %d\n", dfs_seq[i], ans[col[dfs_seq[i]]]);} 109 for (int i = 1; i <= K; i++) printf("%d\n", ans[i]); 110 } 111 112 int main() 113 { 114 Init(); 115 Solve(); 116 }
于是这道题就成了RMQ预处理之后的O(N)乱搞题,然而看了题解之后异常崩溃。
有这样一个结论:每个政党中的最远距离点对,必然有一个点是该政党dep最深的点。仔细考虑没有理由反驳…
于是题目变得很水,找到每个党派的dep最深点,再顺次枚举该党派的所有点,找到lca求值更新答案即可。复杂度O(nlogn)。