BZOJ2870 最长道路
题意:给定树,有点权。求一条路径使得最小点权 * 总点数最大。只需输出这个最大值。5w。
解:树上路径问题,点分治。
考虑合并两个子树的时候,答案的形式是val1 * (d1 + d2),当1是新插入的节点的时候,只需在val比它大的点中选出一个最大的d2,这树状数组就可以做到。
当2是新插入的节点时候,好像需要凸包了?但是我们完全不虚啊,因为我们倒序枚举子树就能让2在1之前插入。
于是正反枚举两次子树,拿树状数组维护一下后缀最大值就行了。
复杂度O(nlog2n)
1 /** 2 * There is no end though there is a start in space. ---Infinity. 3 * It has own power, it ruins, and it goes though there is a start also in the star. ---Finite. 4 * Only the person who was wisdom can read the most foolish one from the history. 5 * The fish that lives in the sea doesn't know the world in the land. 6 * It also ruins and goes if they have wisdom. 7 * It is funnier that man exceeds the speed of light than fish start living in the land. 8 * It can be said that this is an final ultimatum from the god to the people who can fight. 9 * 10 * Steins;Gate 11 */ 12 13 #include <bits/stdc++.h> 14 15 #define forson(x, i) for(int i = e[x]; i; i = edge[i].nex) 16 17 typedef long long LL; 18 const int N = 50010, INF = 0x3f3f3f3f; 19 20 struct Edge { 21 int nex, v; 22 }edge[N << 1], edge2[N << 1]; int tp, tp2; 23 24 int e[N], n, siz[N], _n, root, small, e2[N], xx, d[N], Val[N]; 25 LL val[N], X[N], ans; 26 bool del[N]; 27 28 inline void add(int x, int y) { 29 tp++; 30 edge[tp].v = y; 31 edge[tp].nex = e[x]; 32 e[x] = tp; 33 return; 34 } 35 36 inline void add2(int x, int y) { 37 tp2++; 38 edge2[tp2].v = y; 39 edge2[tp2].nex = e2[x]; 40 e2[x] = tp2; 41 return; 42 } 43 44 namespace ta { 45 int ta[N]; 46 inline void add(int x, int v) { 47 x = xx + 1 - x; 48 for(int i = x; i <= xx; i += i & (-i)) { 49 ta[i] = std::max(ta[i], v); 50 } 51 return; 52 } 53 inline void del(int x) { 54 x = xx + 1 - x; 55 for(int i = x; i <= xx; i += i & (-i)) { 56 ta[i] = -INF; 57 } 58 return; 59 } 60 inline int getMax(int x) { 61 x = xx + 1 - x; 62 int ans = -INF; 63 for(int i = x; i; i -= i & (-i)) { 64 ans = std::max(ans, ta[i]); 65 } 66 return ans; 67 } 68 } 69 70 void getroot(int x, int f) { 71 siz[x] = 1; 72 int large = 0; 73 forson(x, i) { 74 int y = edge[i].v; 75 if(y == f || del[y]) continue; 76 getroot(y, x); 77 siz[x] += siz[y]; 78 if(siz[y] > large) { 79 large = siz[y]; 80 } 81 } 82 if(_n - siz[x] > large) { 83 large = _n - siz[x]; 84 } 85 if(small > large) { 86 small = large; 87 root = x; 88 } 89 return; 90 } 91 92 void DFS_1(int x, int f) { 93 siz[x] = 1; 94 d[x] = d[f] + 1; 95 Val[x] = std::min(Val[f], (int)val[x]); 96 ans = std::max(ans, X[Val[x]] * (d[x] + ta::getMax(Val[x]))); 97 forson(x, i) { 98 int y = edge[i].v; 99 if(del[y] || y == f) continue; 100 DFS_1(y, x); 101 siz[x] += siz[y]; 102 } 103 return; 104 } 105 106 void DFS_2(int x, int f) { 107 ta::add(Val[x], d[x] + 1); 108 forson(x, i) { 109 int y = edge[i].v; 110 if(y == f || del[y]) continue; 111 DFS_2(y, x); 112 } 113 return; 114 } 115 116 void DFS_3(int x, int f) { 117 ta::del(Val[x]); 118 forson(x, i) { 119 int y = edge[i].v; 120 if(del[y] || y == f) { 121 continue; 122 } 123 DFS_3(y, x); 124 } 125 return; 126 } 127 128 void poi_div(int x) { 129 small = INF; 130 getroot(x, 0); 131 x = root; 132 133 d[x] = 0; 134 Val[x] = val[x]; 135 ta::add(Val[x], 1); 136 forson(x, i) { 137 int y = edge[i].v; 138 if(del[y]) continue; 139 DFS_1(y, x); 140 DFS_2(y, x); 141 } 142 DFS_3(x, 0); 143 // --------- 144 for(int i = e2[x]; i; i = edge2[i].nex) { 145 int y = edge2[i].v; 146 if(del[y]) continue; 147 DFS_1(y, x); 148 DFS_2(y, x); 149 } 150 ans = std::max(ans, X[val[x]] * ta::getMax(val[x])); 151 DFS_3(x, 0); 152 153 del[x] = 1; 154 forson(x, i) { 155 int y = edge[i].v; 156 if(del[y]) continue; 157 _n = siz[y]; 158 poi_div(y); 159 } 160 return; 161 } 162 163 int main() { 164 165 scanf("%d", &n); 166 for(int i = 1; i <= n; i++) { 167 scanf("%lld", &val[i]); 168 X[i] = val[i]; 169 } 170 std::sort(X + 1, X + n + 1); 171 xx = std::unique(X + 1, X + n + 1) - X - 1; 172 for(int i = 1; i <= n; i++) { 173 val[i] = std::lower_bound(X + 1, X + xx + 1, val[i]) - X; 174 } 175 ans = X[xx]; 176 for(int i = 1, x, y; i < n; i++) { 177 scanf("%d%d", &x, &y); 178 add(x, y); add(y, x); 179 } 180 for(int x = 1; x <= n; x++) { 181 forson(x, i) { 182 add2(x, edge[i].v); 183 } 184 } 185 186 poi_div(1); 187 188 printf("%lld\n", ans); 189 return 0; 190 }
题外话:感觉能树形DP,但是要线段树合并 + 凸包合并,虚的一批...
还发现了一个O(nlogn)的做法,只需多叉转二叉然后O(n) - O(1)lca即可实现,瓶颈在于排序...
然而这题是边分治模板题...