zoukankan      html  css  js  c++  java
  • LOJ#2249 购票

    解:转移方程写出来,发现是斜率优化。因为在树上,考虑CDQ分治 + 点分治的方法...

    每次找到重心,然后先递归解决上面的子树。然后把上面子树的凸包搞出来,下面每个点在凸包上二分找最优决策。

    重心自己不参与上面子树的递归,单独给下面转移。

    注意这个东西斜率可能有负数,不能简单乘到不等式另一边。

    二分的写法要注意。

    每个点的转移还有个深度限制,所以要按照深度限制把询问(待转移的点)排序,然后一边动态加凸包一边二分回答询问。

      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 
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ", pos);
    167             pos = fa[pos];
    168         }
    169         if(!top) continue;
    170         int l = 1, r = top;
    171         //printf("l = %d r = top = %d 
    ", l, r);
    172         while(l < r) {
    173             int mid = (l + r) >> 1;
    174             //printf("mid = %d 
    ", 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 
    ", 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 
    ", r);
    188         /// branch search OVER
    189         //printf("Min %lld (%lld - %lld * %lld) 
    ", 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 
    ", 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 
    ", 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 
    ");
    228 
    229     _n = n;
    230     CDQ(1);
    231 
    232     for(int i = 2; i <= n; i++) {
    233         printf("%lld
    ", f[i]);
    234     }
    235     return 0;
    236 }
    AC代码
  • 相关阅读:
    CAPTCHA---验证码 ---Security code
    Thymeleaf利用layout.html文件生成页面布局框架
    阿里云和腾讯云免费SSL证书 专题
    完整项目基础架构精简版-实现权限管理
    Android 基于XMPP Smack openfire 开发的聊天室
    Android 基于Bmob平台数据管理常用方法整理
    Android图表和图形创建库:EazeGraph
    Android 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果
    Android MagicIndicator系列之一 —— 使用MagicIndicator打造千变万化的ViewPager指示器
    Android 比较两个时间段是否有交集或重复
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10549304.html
Copyright © 2011-2022 走看看