解:轉移方程寫出來,發現是斜率優化。由於在樹上,考慮CDQ分治 + 點分治的方法...c++
每次找到重心,而後先遞歸解決上面的子樹。而後把上面子樹的凸包搞出來,下面每一個點在凸包上二分找最優決策。ide
重心本身不參與上面子樹的遞歸,單獨給下面轉移。優化
注意這個東西斜率可能有負數,不能簡單乘到不等式另外一邊。spa
二分的寫法要注意。rest
每一個點的轉移還有個深度限制,因此要按照深度限制把詢問(待轉移的點)排序,而後一邊動態加凸包一邊二分回答詢問。code
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 200010, INF = 0x3f3f3f3f; 5 const double eps = 1e-12; 6 7 struct Edge { 8 int nex, v; 9 LL len; 10 }edge[N << 1]; int tp = 1; 11 12 int e[N], _n, root, small, siz[N], deep[N], fa[N], stk[N], top2, stk2[N], SMALL, n; 13 LL p[N], q[N], lim[N], d[N], f[N]; 14 bool del[N]; 15 16 inline bool cmp_l(const int &a, const int &b) { 17 return lim[a] < lim[b]; 18 } 19 20 template <class T> inline void Min(T &a, const T &b) { 21 a > b ? a = b : 0; 22 return; 23 } 24 25 inline void add(int x, int y, LL z) { 26 tp++; 27 edge[tp].v = y; 28 edge[tp].len = z; 29 edge[tp].nex = e[x]; 30 e[x] = tp; 31 return; 32 } 33 34 void DFS_1(int x, int f) { 35 deep[x] = deep[f] + 1; 36 fa[x] = f; 37 for(int i = e[x]; i; i = edge[i].nex) { 38 int y = edge[i].v; 39 if(y == f) continue; 40 d[y] = d[x] + edge[i].len; 41 DFS_1(y, x); 42 } 43 return; 44 } 45 46 void getroot(int x, int f) { 47 //printf("getroot : %d %d \n", x, f); 48 int large = 0; 49 siz[x] = 1; 50 Min(SMALL, deep[x]); 51 for(int i = e[x]; i; i = edge[i].nex) { 52 int y = edge[i].v; 53 if(del[y] || y == f) continue; 54 getroot(y, x); 55 siz[x] += siz[y]; 56 if(siz[y] > large) large = siz[y]; 57 } 58 large = std::max(large, _n - siz[x]); 59 if(small > large) { 60 small = large; 61 root = x; 62 } 63 return; 64 } 65 66 void DFS_2(int x, int f) { 67 stk2[++top2] = x; 68 //printf("DFS2 : %d \n", x); 69 for(int i = e[x]; i; i = edge[i].nex) { 70 int y = edge[i].v; 71 if(del[y] || y == f) continue; 72 DFS_2(y, x); 73 } 74 return; 75 } 76 77 inline bool check(int a, int b, int c) { 78 return (long double)(f[b] - f[a]) / (d[b] - d[a]) + eps > (long double)(f[c] - f[b]) / (d[c] - d[b]); 79 } 80 81 void DFS_3(int x, int f) { 82 siz[x] = 1; 83 for(int i = e[x]; i; i = edge[i].nex) { 84 int y = edge[i].v; 85 if(del[y] || y == f) continue; 86 DFS_3(y, x); 87 siz[x] += siz[y]; 88 } 89 return; 90 } 91 92 void DFS_4(int x, int father, int rt) { 93 if(x != rt && d[rt] >= lim[x]) { 94 Min(f[x], f[rt] - p[x] * d[rt]); 95 /*if(x == 5) { 96 printf("f %d = %lld rt = %d \n", x, f[x], rt); 97 }*/ 98 } 99 for(int i = e[x]; i; i = edge[i].nex) { 100 int y = edge[i].v; 101 if(y == father || del[y]) continue; 102 DFS_4(y, x, rt); 103 } 104 return; 105 } 106 107 void CDQ(int x) { 108 109 //printf("CDQ : %d _n = %d \n", x, _n); 110 111 if(_n == 1) { 112 f[x] += p[x] * d[x] + q[x]; 113 del[x] = 1; 114 //printf("1 : f [ %d ] = %lld \n", x, f[x]); 115 return; 116 } 117 118 SMALL = small = INF; 119 getroot(x, 0); 120 int tempsmall = SMALL; 121 x = root; 122 DFS_3(x, 0); 123 del[x] = 1; 124 /// 125 if(del[fa[x]]) { 126 f[x] += p[x] * d[x] + q[x]; 127 128 //printf("2 : f [ %d ] = %lld \n", x, f[x]); 129 130 DFS_4(x, 0, x); 131 for(int i = e[x]; i; i = edge[i].nex) { 132 int y = edge[i].v; 133 if(del[y]) continue; 134 _n = siz[y]; 135 CDQ(y); 136 } 137 return; 138 } 139 _n = siz[fa[x]]; 140 CDQ(fa[x]); 141 142 /** 143 while(top > 1 && check(stk[top - 1], stk[top], temp)) { 144 top--; 145 } 146 */ 147 top2 = 0; 148 DFS_2(x, 0); 149 std::sort(stk2 + 1, stk2 + top2 + 1, cmp_l); 150 std::reverse(stk2 + 1, stk2 + top2 + 1); 151 int pos = fa[x], top = 0; 152 //printf(" ----------------- x = %d fa[x] = %d \n", x, fa[x]); 153 /*printf("sort : "); 154 for(int i = 1; i <= top2; i++) { 155 printf("%d ", stk2[i]); 156 } 157 puts("");*/ 158 for(int i = 1; i <= top2; i++) { 159 int xx = stk2[i]; 160 while(pos && deep[pos] >= tempsmall && d[pos] >= lim[xx]) { 161 /// insert p 162 while(top > 1 && check(pos, stk[top], stk[top - 1])) { 163 top--; 164 } 165 stk[++top] = pos; 166 //printf("insert pos = %d \n", pos); 167 pos = fa[pos]; 168 } 169 if(!top) continue; 170 int l = 1, r = top; 171 //printf("l = %d r = top = %d \n", l, r); 172 while(l < r) { 173 int mid = (l + r) >> 1; 174 //printf("mid = %d \n", mid); 175 if(l < mid && p[xx] > (long double)(f[stk[mid]] - f[stk[mid - 1]]) / (d[stk[mid]] - d[stk[mid - 1]])) { 176 r = mid - 1; 177 } 178 else if(mid < r && p[xx] < (long double)(f[stk[mid + 1]] - f[stk[mid]]) / (d[stk[mid +1]] - d[stk[mid]])) { 179 //printf("-------------- %lld * %lld < %lld \n", p[xx], (d[stk[mid +1]] - d[stk[mid]]), (f[stk[mid + 1]] - f[stk[mid]])); 180 l = mid + 1; 181 } 182 else { 183 r = mid; 184 break; 185 } 186 } 187 //printf("r = %d \n", r); 188 /// branch search OVER 189 //printf("Min %lld (%lld - %lld * %lld) \n", f[xx], f[stk[r]], p[xx], d[stk[r]]); 190 Min(f[xx], f[stk[r]] - p[xx] * d[stk[r]]); 191 //printf("%d -> %d f[%d] = %lld \n", stk[r], xx, xx, f[xx]); 192 } 193 194 f[x] += p[x] * d[x] + q[x]; 195 DFS_4(x, 0, x); 196 //printf("3 : f [ %d ] = %lld += %lld * %lld + %lld \n", x, f[x], p[x], d[x], q[x]); 197 198 /// rest 199 for(int i = e[x]; i; i = edge[i].nex) { 200 int y = edge[i].v; 201 if(del[y]) continue; 202 _n = siz[y]; 203 CDQ(y); 204 } 205 return; 206 } 207 208 int main() { 209 210 freopen("in.in", "r", stdin); 211 //freopen("my.out", "w", stdout); 212 213 memset(f, 0x3f, sizeof(f)); 214 f[1] = 0; 215 int ttt; LL z; 216 scanf("%d%d", &n, &ttt); 217 for(int i = 2, x; i <= n; i++) { 218 scanf("%d%lld%lld%lld%lld", &x, &z, &p[i], &q[i], &lim[i]); 219 add(x, i, z); add(i, x, z); 220 } 221 /// input over 222 DFS_1(1, 0); 223 for(int i = 2; i <= n; i++) { 224 lim[i] = std::max(0ll, d[i] - lim[i]); 225 } 226 227 //printf("OVER \n"); 228 229 _n = n; 230 CDQ(1); 231 232 for(int i = 2; i <= n; i++) { 233 printf("%lld\n", f[i]); 234 } 235 return 0; 236 }