UVALive 7148 LRIP 14年上海区域赛K题 树分治
题意 n个点组成一棵树, 带有点权。 求最长不降的路径的长度, 且路径上最大值最小值之差不超过D。
显然是树分治, 但是分治之后如何维护答案呢。
假设当前重心为g, 分别记录g出发不降路径的长度,以及最大值, 和不升路径的长度以及最小值。
这里用到一个map和二分, 线段树也可以, 但是如果用线段树还要考虑负值, 再加上线段树的clear以及稍微暴力的查询。 常数大小不好说。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef pair <int, int> pii; 4 const int maxn = 1e5 + 5; 5 vector <int> G[maxn]; 6 int val[maxn], siz[maxn], n, D; 7 bool centroid[maxn]; 8 void init() { 9 for (int i = 0; i < maxn; i++) { 10 G[i].clear(); 11 } 12 memset(centroid, false, sizeof centroid); 13 } 14 void dfs(int u, int father){ 15 siz[u] = 1; 16 for (int v: G[u]){ 17 if (v != father && !centroid[v]){ 18 dfs(v, u); 19 siz[u] += siz[v]; 20 } 21 } 22 } 23 pii FindCentroid(int u, int father, int t) { 24 pii res = make_pair(INT_MAX, -1); 25 int s = 1, m = 0; 26 for (int v: G[u]) { 27 if (v == father || centroid[v]) { 28 continue; 29 } 30 res = min(res, FindCentroid(v, u, t)); 31 m = max(m, siz[v]); 32 s += siz[v]; 33 } 34 siz[u] = s; 35 m = max(m, t-s); 36 return min(res, make_pair(m, u)); 37 } 38 map <int, int> work; 39 void update(int v, int len) { 40 auto it = work.lower_bound(v); 41 if (it != work.end() && it->second >= len) { 42 return; 43 } 44 work[v] = len; 45 } 46 void dfs_up(int u, int father, int d) { 47 if (val[u] > val[father]) { 48 return; 49 } 50 update(val[u], d); 51 for (int v: G[u]) { 52 if (v != father && !centroid[v]) { 53 dfs_up(v, u, d+1); 54 } 55 } 56 } 57 int res; 58 void dfs_down(int u, int father, int d) { 59 if (val[u] < val[father]) { 60 return; 61 } 62 auto it = work.lower_bound(val[u]-D); 63 if (it != work.end()) { 64 res = max(res, it->second+1+d); 65 } 66 for (int v: G[u]) { 67 if (!centroid[v] && v != father) { 68 dfs_down(v, u, d+1); 69 } 70 } 71 } 72 73 void preSolve(int g, vector <int> &son) { 74 work.clear(); 75 work[val[g]] = 0; 76 for (int v: son) { 77 if (val[v] >= val[g]) { 78 dfs_down(v, g, 1); 79 } 80 if (val[v] <= val[g]) { 81 dfs_up(v, g, 1); 82 } 83 } 84 } 85 void solve(int u) { 86 dfs(u, 0); 87 int g = FindCentroid(u, 0, siz[u]).second; 88 vector <int> son; 89 for (int v: G[g]) { 90 if (!centroid[v]) { 91 son.push_back(v); 92 } 93 } 94 preSolve(g, son); 95 reverse(son.begin(), son.end()); 96 preSolve(g, son); 97 centroid[g] = true; 98 for (int v: G[g]) { 99 if (!centroid[v]) { 100 solve(v); 101 } 102 } 103 } 104 int main() { 105 // freopen("in.txt", "r", stdin); 106 int T, cas = 1; 107 scanf ("%d", &T); 108 while (T--) { 109 init(); 110 scanf ("%d%d", &n, &D); 111 for (int i = 1; i <= n; i++) { 112 scanf ("%d", val+i); 113 } 114 for (int i = 1; i < n; i++) { 115 int u, v; 116 scanf ("%d%d", &u, &v); 117 G[u].push_back(v); 118 G[v].push_back(u); 119 } 120 res = 1; 121 solve(1); 122 printf("Case #%d: %d\n", cas++, res); 123 } 124 return 0; 125 }