LOJ#2249 購票

解:轉移方程寫出來,發現是斜率優化。由於在樹上,考慮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 }
AC代碼
相關文章
相關標籤/搜索