zoukankan      html  css  js  c++  java
  • 动态点分治

    大概就是把点分树建出来,维护每个点的信息和全局信息。

    修改的时候考虑一个点对它点分树祖先的影响。

    树上与距离有关的问题,考虑动态点分治。

    例题:

    洛谷P2056 捉迷藏

    带修树上最远黑色点对。

    这道题难点根本不在动态点分治,完全在于堆(们)好吧!!!我被这三种堆虐的死去活来,然后又T飞...换了O(1)lca才过。

     1 struct PQ {
     2     std::priority_queue<int> a, b;
     3     inline void push(int x) {
     4         a.push(x);
     5         return;
     6     }
     7     inline void update() {
     8         while(a.size() && b.size() && a.top() == b.top()) {
     9             a.pop();
    10             b.pop();
    11         }
    12         return;
    13     }
    14     inline void pop() {
    15         update();
    16         if(a.size()) {
    17             a.pop();
    18         }
    19         return;
    20     }
    21     inline void del(int x) {
    22         b.push(x);
    23         return;
    24     }
    25     inline int top() {
    26         update();
    27         return a.size() ? a.top() : -INF;
    28     }
    29     inline int size() {
    30         return std::max((int)(a.size() - b.size()), 0);
    31     }
    32     inline bool empty() {
    33         return a.size() <= b.size();
    34     }
    35 };
    可删堆

    Ql[x]维护当前节点管辖的连通块到FA[x]的距离。

    Qs[x]维护每个子节点Ql的最大值(包括他自己的距离)。

    还有个全局的ans维护所有Qs的前两大之和(答案)。

      1 // luogu-judger-enable-o2
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <queue>
      5 
      6 const int N = 200010, INF = 0x3f3f3f3f;
      7 
      8 inline void read(int &x) {
      9     x = 0;
     10     char c = getchar();
     11     while(c < '0' || c > '9') {
     12         c = getchar();
     13     }
     14     while(c >= '0' && c <= '9') {
     15         x = (x << 3) + (x << 1) + c - 48;
     16         c = getchar();
     17     }
     18     return;
     19 }
     20 
     21 struct Edge {
     22     int nex, v;
     23 }edge[N << 1], EDGE[N << 1]; int tp, TP;
     24 
     25 struct PQ {
     26     std::priority_queue<int> a, b;
     27     inline void push(int x) {
     28         a.push(x);
     29         return;
     30     }
     31     inline void update() {
     32         while(a.size() && b.size() && a.top() == b.top()) {
     33             a.pop();
     34             b.pop();
     35         }
     36         return;
     37     }
     38     inline void pop() {
     39         update();
     40         if(a.size()) {
     41             a.pop();
     42         }
     43         return;
     44     }
     45     inline void del(int x) {
     46         b.push(x);
     47         return;
     48     }
     49     inline int top() {
     50         update();
     51         return a.size() ? a.top() : -INF;
     52     }
     53     inline int size() {
     54         return std::max((int)(a.size() - b.size()), 0);
     55     }
     56     inline bool empty() {
     57         return a.size() <= b.size();
     58     }
     59 }Ql[N], Qs[N], ans;
     60 
     61 int e[N], dist[N], n, root, _n, small, siz[N], fr[N], E[N], FA[N], d[N], Cnt, pw[N << 1], fa[N];
     62 int pos[N << 1], num, ST[N << 1][20];
     63 bool del[N], col[N];
     64 
     65 inline void add(int x, int y) {
     66     tp++;
     67     edge[tp].v = y;
     68     edge[tp].nex = e[x];
     69     e[x] = tp;
     70     return;
     71 }
     72 
     73 inline void ADD(int x, int y) {
     74     TP++;
     75     EDGE[TP].v = y;
     76     EDGE[TP].nex = E[x];
     77     E[x] = TP;
     78     return;
     79 }
     80 
     81 inline int lca(int x, int y) {
     82     x = pos[x];
     83     y = pos[y];
     84     if(x > y) std::swap(x, y);
     85     int t = pw[y - x + 1];
     86     if(dist[ST[x][t]] < dist[ST[y - (1 << t) + 1][t]]) {
     87         return ST[x][t];
     88     }
     89     else
     90         return ST[y - (1 << t) + 1][t];
     91 }
     92 
     93 inline int dis(int x, int y) {
     94     return dist[x] + dist[y] - dist[lca(x, y)] * 2;
     95 }
     96 
     97 inline void prework() {
     98     for(int i = 2; i <= num; i++) {
     99         pw[i] = pw[i >> 1] + 1;
    100     }
    101     for(int j = 1; j <= pw[num]; j++) {
    102         for(int i = 1; i <= num; i++) {
    103             if(dist[ST[i][j - 1]] < dist[ST[i + (1 << (j - 1))][j - 1]])
    104                 ST[i][j] = ST[i][j - 1];
    105             else
    106                 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
    107         }
    108     }
    109     return;
    110 }
    111 
    112 void DFS_0(int x, int father) {
    113     fa[x] = father;
    114     dist[x] = dist[father] + 1;
    115     pos[x] = ++num;
    116     ST[num][0] = x;
    117     for(int i = e[x]; i; i = edge[i].nex) {
    118         int y = edge[i].v;
    119         if(y == father) continue;
    120         DFS_0(y, x);
    121         ST[++num][0] = x;
    122     }
    123     return;
    124 }
    125 
    126 void get_root(int x, int father) {
    127     int large = 0;
    128     siz[x] = 1;
    129     for(int i = e[x]; i; i = edge[i].nex) {
    130         int y = edge[i].v;
    131         if(del[y] || y == father) {
    132             continue;
    133         }
    134         get_root(y, x);
    135         siz[x] += siz[y];
    136         large = std::max(large, siz[y]);
    137     }
    138     large = std::max(large, _n - siz[x]);
    139     if(small > large) {
    140         small = large;
    141         root = x;
    142     }
    143     return;
    144 }
    145 
    146 void DFS_1(int x, int father, int rt) {
    147     Ql[rt].push(d[x]);
    148     //printf("Ql %d push %d %d 
    ", rt, x, d[x]);
    149     siz[x] = 1;
    150     d[x] = d[father] + 1;
    151     for(int i = e[x]; i; i = edge[i].nex) {
    152         int y = edge[i].v;
    153         if(del[y] || y == father) continue;
    154         DFS_1(y, x, rt);
    155         siz[x] += siz[y];
    156     }
    157     return;
    158 }
    159 
    160 void poi_div(int x, int father) {
    161     small = INF;
    162     get_root(x, 0);
    163     x = root;
    164     FA[x] = father;
    165     if(father) ADD(father, x);
    166     Ql[x].push(d[x]);
    167     //printf("Ql %d push %d %d 
    ", x, x, d[x]);
    168 
    169     d[x] = 0;
    170     for(int i = e[x]; i; i = edge[i].nex) {
    171         int y = edge[i].v;
    172         if(del[y]) continue;
    173         DFS_1(y, x, x);
    174     }
    175 
    176     del[x] = 1;
    177     for(int i = e[x]; i; i = edge[i].nex) {
    178         int y = edge[i].v;
    179         if(del[y]) continue;
    180         _n = siz[y];
    181         poi_div(y, x);
    182     }
    183     return;
    184 }
    185 
    186 void DFS_2(int x) {
    187     //printf("DFS2 : x = %d 
    ", x);
    188     for(int i = E[x]; i; i = EDGE[i].nex) {
    189         int y = EDGE[i].v;
    190         DFS_2(y);
    191         int temp = Ql[y].top();
    192         Qs[x].push(temp);
    193         //printf("x = %d y = %d push %d %d 
    ", x, y, temp.x, temp.d);
    194     }
    195     Qs[x].push(0);
    196     /// get Answer
    197     int temp = Qs[x].top();
    198     Qs[x].pop();
    199     if(Qs[x].size()) {
    200         int Ans = Qs[x].top() + temp;
    201         ans.push(Ans);
    202     }
    203     Qs[x].push(temp);
    204     return;
    205 }
    206 
    207 inline int getAns() {
    208     if(Cnt == 0) return -1;
    209     if(Cnt == 1) return 0;
    210     return ans.top();
    211 }
    212 
    213 char str[3];
    214 
    215 inline int cal_ans(int x) {
    216     int t = Qs[x].top();
    217     Qs[x].pop();
    218     int ans = t + Qs[x].top();
    219     Qs[x].push(t);
    220     return ans;
    221 }
    222 
    223 inline void change(int x) {
    224     if(col[x] == 0) Cnt--;
    225     else Cnt++;
    226     bool f = col[x];
    227     col[x] ^= 1;
    228 
    229     if(f) {
    230         ans.del(cal_ans(x));
    231         Qs[x].push(0);
    232         ans.push(cal_ans(x));
    233     }
    234     else {
    235         ans.del(cal_ans(x));
    236         Qs[x].del(0);
    237         ans.push(cal_ans(x));
    238     }
    239 
    240     int first_x = x;
    241     while(FA[x]) {
    242         int F = FA[x];
    243         int temp = Ql[x].top();
    244         if(f)
    245             Ql[x].push(dis(F, first_x));
    246         else
    247             Ql[x].del(dis(F, first_x));
    248         if(temp != Ql[x].top()) {
    249             int temp_ans = cal_ans(F);
    250             Qs[F].del(temp);
    251             Qs[F].push(Ql[x].top());
    252             int now_ans = cal_ans(F);
    253             if(now_ans != temp_ans) {
    254                 ans.del(temp_ans);
    255                 ans.push(now_ans);
    256             }
    257         }
    258         x = F;
    259     }
    260     return;
    261 }
    262 
    263 int main() {
    264     read(n);
    265     for(int i = 1, x, y; i < n; i++) {
    266         read(x); read(y);
    267         add(x, y); add(y, x);
    268     }
    269 
    270     DFS_0(1, 0);
    271     prework();
    272     Cnt = _n = n;
    273     poi_div(1, 0);
    274     for(int i = 1; i <= n; i++) {
    275         if(!FA[i]) root = i;
    276         //printf("FA %d = %d 
    ", i, FA[i]);
    277     }
    278     DFS_2(root);
    279 
    280 
    281     int q;
    282     read(q);
    283     for(int i = 1, x; i <= q; i++) {
    284         scanf("%s", str);
    285         if(str[0] == 'G') {
    286             printf("%d
    ", getAns());
    287         }
    288         else {
    289             read(x);
    290             change(x);
    291         }
    292     }
    293 
    294     return 0;
    295 }
    AC代码

    感觉动态点分治主要是难在理清思路上......

    洛谷P3345 幻想乡战略游戏

    动态带权重心。

    这TM又是个毒瘤题...昨天看题解脑袋全是糊的。代码错上天。今天自己YY出了解法终于写对了......

    考虑随机选一个点,如何调整?如果有一个子树里面siz比总的一半要大,就过去。

    然后我们利用点分树结构,去到那个子树的连通块内的重心。这样只要找logn次即可。

    考虑如何判断:要查询以x为根的时候他的一个子节点的权值和,显然一个DFS序树状数组就没了。

    这样就能够找到答案所在的点。那么如何统计答案呢?

    正着来实在是奥妙重重,我完全搞不倒,所以考虑回溯时累加。

    从y回溯到x之后,把x的点分子树中除了y子树的代价都加上。y子树内的之前统计了。

    我们需要SIZ[x]表示x的点分子树内的总个数,dx[x]表示x的点分子树内全部到x的总距离。df[x]表示x的点分子树全部到FA[x]的总距离。

    利用这三个数组可以把y子树挖掉然后计算其它的总代价。当然我们需要一个O(1)两点在原树间的距离。

    修改就沿途修改这三个数组。

    实现细节:ask的时候在点分树上面走。near[x]表示x的点分子树中,原树距离FA[x]最近的点。

    顺便%一下本题的线段树二分解法,神奇。

      1 #include <cstdio>
      2 #include <algorithm>
      3 
      4 typedef long long LL;
      5 const int N = 100010, INF = 0x3f3f3f3f;
      6 
      7 struct Edge {
      8     int nex, v;
      9     LL len;
     10 }edge[N << 1], EDGE[N << 1]; int tp, TP;
     11 
     12 int n, e[N], E[N], FA[N], ROOT, root, fa[N], near[N];
     13 int num, pos[N], ST[N << 1][20], pw[N << 1], deep[N], siz[N], _n, small;
     14 LL dist[N];
     15 bool del[N];
     16 LL dx[N], df[N], TOT, SIZ[N];
     17 
     18 namespace ta {
     19     int pos[N], siz[N], num;
     20     LL ta[N];
     21     inline void add(int x, LL v) {
     22         for(int i = pos[x]; i <= n; i += i & (-i)) {
     23             ta[i] += v;
     24         }
     25         return;
     26     }
     27     inline LL getSum(int x) {
     28         LL ans = 0;
     29         for(int i = x; i >= 1; i -= i & (-i)) {
     30             ans += ta[i];
     31         }
     32         return ans;
     33     }
     34     inline LL ask(int x) {
     35         return getSum(pos[x] + siz[x] - 1) - getSum(pos[x] - 1);
     36     }
     37 }
     38 
     39 inline void add(int x, int y, LL z) {
     40     tp++;
     41     edge[tp].v = y;
     42     edge[tp].len = z;
     43     edge[tp].nex = e[x];
     44     e[x] = tp;
     45     return;
     46 }
     47 
     48 inline void ADD(int x, int y, LL z = 0) {
     49     TP++;
     50     EDGE[TP].v = y;
     51     EDGE[TP].len = z;
     52     EDGE[TP].nex = E[x];
     53     E[x] = TP;
     54     return;
     55 }
     56 
     57 void DFS_0(int x, int f) {
     58     pos[x] = ++num;
     59     ST[num][0] = x;
     60     deep[x] = deep[f] + 1;
     61     fa[x] = f;
     62     ta::siz[x] = 1;
     63     ta::pos[x] = ++ta::num;
     64     for(int i = e[x]; i; i = edge[i].nex) {
     65         int y = edge[i].v;
     66         if(y == f) continue;
     67         dist[y] = dist[x] + edge[i].len;
     68         DFS_0(y, x);
     69         ta::siz[x] += ta::siz[y];
     70         ST[++num][0] = x;
     71     }
     72     return;
     73 }
     74 
     75 inline void prework() {
     76     for(int i = 2; i <= num; i++) {
     77         pw[i] = pw[i >> 1] + 1;
     78     }
     79     for(int j = 1; j <= pw[num]; j++) {
     80         for(int i = 1; i + (1 << j) - 1 <= num; i++) {
     81             if(deep[ST[i][j - 1]] < deep[ST[i + (1 << (j - 1))][j - 1]])
     82                 ST[i][j] = ST[i][j - 1];
     83             else
     84                 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
     85         }
     86     }
     87     return;
     88 }
     89 
     90 inline int lca(int x, int y) {
     91     x = pos[x]; y = pos[y];
     92     if(x > y) std::swap(x, y);
     93     int t = pw[y - x + 1];
     94     if(deep[ST[x][t]] < deep[ST[y - (1 << t) + 1][t]])
     95         return ST[x][t];
     96     else
     97         return ST[y - (1 << t) + 1][t];
     98 }
     99 
    100 inline LL dis(int x, int y) {
    101     return dist[x] + dist[y] - 2 * dist[lca(x, y)];
    102 }
    103 
    104 void get_root(int x, int f) {
    105     siz[x] = 1;
    106     int large = 0;
    107     for(int i = e[x]; i; i = edge[i].nex) {
    108         int y = edge[i].v;
    109         if(del[y] || y == f) {
    110             continue;
    111         }
    112         get_root(y, x);
    113         siz[x] += siz[y];
    114         large = std::max(large, siz[y]);
    115     }
    116     large = std::max(large, _n - siz[x]);
    117     if(small > large) {
    118         small = large;
    119         root = x;
    120     }
    121     return;
    122 }
    123 
    124 void DFS_1(int x, int f, int rt) {
    125     siz[x] = 1;
    126     for(int i = e[x]; i; i = edge[i].nex) {
    127         int y = edge[i].v;
    128         if(y == ROOT) {
    129             near[rt] = x;
    130         }
    131         if(del[y] || y == f) continue;
    132         DFS_1(y, x, rt);
    133         siz[x] += siz[y];
    134     }
    135     return;
    136 }
    137 
    138 void poi_div(int x, int father) {
    139     small = INF;
    140     get_root(x, 0);
    141     x = root;
    142     FA[x] = father;
    143     if(father) ADD(father, x);
    144 
    145     ROOT = father;
    146     for(int i = e[x]; i; i = edge[i].nex) {
    147         int y = edge[i].v;
    148         if(del[y]) continue;
    149         DFS_1(y, x, x);
    150     }
    151 
    152     del[x] = 1;
    153     for(int i = e[x]; i; i = edge[i].nex) {
    154         int y = edge[i].v;
    155         if(del[y]) continue;
    156         _n = siz[y];
    157         poi_div(y, x);
    158     }
    159 
    160     if(!near[x]) near[x] = x;
    161     return;
    162 }
    163 
    164 inline void change(int x, LL v) {
    165     TOT += v;
    166     ta::add(x, v);
    167     int first_x = x;
    168     while(x) {
    169         SIZ[x] += v;
    170         if(FA[x]) {
    171             df[x] += v * dis(first_x, FA[x]);
    172         }
    173         dx[x] += v * dis(first_x, x);
    174         x = FA[x];
    175     }
    176     return;
    177 }
    178 
    179 inline LL getSIZ(int x, int f) {
    180     if(fa[x] == f) return ta::ask(x);
    181     else return TOT - ta::ask(f);
    182 }
    183 
    184 int ask(int x, LL &v) {
    185     int ans = x;
    186     for(int i = E[x]; i; i = EDGE[i].nex) {
    187         int y = EDGE[i].v;
    188         if(2 * getSIZ(near[y], x) > TOT) {
    189             ans = y;
    190             break;
    191         }
    192     }
    193     if(ans == x) {
    194         /// now is ans
    195         v = dx[x];
    196         return x;
    197     }
    198     else {
    199         int p = ask(ans, v);
    200         v += dx[x] - df[ans] + (SIZ[x] - SIZ[ans]) * dis(x, p);
    201         return p;
    202     }
    203 }
    204 
    205 int main() {
    206 
    207     int q; LL z;
    208     scanf("%d%d", &n, &q);
    209     for(int i = 1, x, y; i < n; i++) {
    210         scanf("%d%d%lld", &x, &y, &z);
    211         add(x, y, z);
    212         add(y, x, z);
    213     }
    214 
    215     DFS_0(1, 0);
    216     prework();
    217     _n = n;
    218     poi_div(1, 0);
    219 
    220     for(int i = 1; i <= n; i++) {
    221         if(!FA[i]) {
    222             root = i;
    223             break;
    224         }
    225     }
    226 
    227     LL v;
    228     for(int i = 1, x; i <= q; i++) {
    229         scanf("%d%lld", &x, &v);
    230         /// val[x] += y;
    231         change(x, v);
    232         LL t;
    233         ask(root, t);
    234         printf("%lld
    ", t);
    235     }
    236 
    237     return 0;
    238 }
    AC代码

    对拍真是个好东西...

    BZOJ3730 震波

    带修半径k内点权和。

    这个比上面两个好想好写一点,当然写出来又错了一堆...注意不要把first_x写成x。对拍真好用。

    点分树上每个点开一个数据结构维护点分子树内距离它深度为d的权值和。跟上一题一样,从下往上查,减去算重的答案即可。

      1 #include <cstdio>
      2 #include <algorithm>
      3 
      4 const int N = 100010, INF = 0x3f3f3f3f, M = 20000010;
      5 
      6 inline void read(int &x) {
      7     x = 0;
      8     char c = getchar();
      9     while(c < '0' || c > '9') {
     10         c = getchar();
     11     }
     12     while(c >= '0' && c <= '9') {
     13         x = (x << 3) + (x << 1) + c - 48;
     14         c = getchar();
     15     }
     16     return;
     17 }
     18 
     19 struct Edge {
     20     int nex, v;
     21 }edge[N << 1]; int tp;
     22 
     23 int FA[N], e[N], siz[N], n, pos[N], num, ST[N << 1][20], pw[N << 1], deep[N], small, root, _n, d[N];
     24 bool del[N];
     25 int val[N];
     26 
     27 namespace seg {
     28     int tot, sum[M], ls[M], rs[M], rt[N << 1];
     29     void add(int p, int v, int l, int r, int &o) {
     30         if(!o) o = ++tot;
     31         sum[o] += v;
     32         if(l == r) {
     33             return;
     34         }
     35         int mid = (l + r) >> 1;
     36         if(p <= mid) add(p, v, l, mid, ls[o]);
     37         else add(p, v, mid + 1, r, rs[o]);
     38         return;
     39     }
     40     inline void insert(int id, int p, int v) {
     41         add(p + 1, v, 1, n, rt[id]);
     42         return;
     43     }
     44     int getSum(int L, int R, int l, int r, int o) {
     45         if(!o) return 0;
     46         if(L <= l && r <= R) return sum[o];
     47         int mid = (l + r) >> 1, ans = 0;
     48         if(L <= mid) ans += getSum(L, R, l, mid, ls[o]);
     49         if(mid < R) ans += getSum(L, R, mid + 1, r, rs[o]);
     50         return ans;
     51     }
     52     inline int ask(int id, int L, int R) {
     53         if(L > R) return 0;
     54         return getSum(L + 1, R + 1, 1, n, rt[id]);
     55     }
     56 }
     57 
     58 inline void add(int x, int y) {
     59     tp++;
     60     edge[tp].v = y;
     61     edge[tp].nex = e[x];
     62     e[x] = tp;
     63     return;
     64 }
     65 
     66 void DFS_0(int x, int f) {
     67     pos[x] = ++num;
     68     ST[num][0] = x;
     69     deep[x] = deep[f] + 1;
     70     for(int i = e[x]; i; i = edge[i].nex) {
     71         int y = edge[i].v;
     72         if(y == f) continue;
     73         DFS_0(y, x);
     74         ST[++num][0] = x;
     75     }
     76     return;
     77 }
     78 
     79 inline void prework() {
     80     for(int i = 2; i <= num; i++) {
     81         pw[i] = pw[i >> 1] + 1;
     82     }
     83     for(int j = 1; j <= pw[num]; j++) {
     84         for(int i = 1; i + (1 << j) - 1 <= num; i++) {
     85             if(deep[ST[i][j - 1]] < deep[ST[i + (1 << (j - 1))][j - 1]])
     86                 ST[i][j] = ST[i][j - 1];
     87             else
     88                 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
     89         }
     90     }
     91     return;
     92 }
     93 
     94 inline int lca(int x, int y) {
     95     x = pos[x];
     96     y = pos[y];
     97     if(x > y) std::swap(x, y);
     98     int t = pw[y - x + 1];
     99     if(deep[ST[x][t]] < deep[ST[y - (1 << t) + 1][t]])
    100         return ST[x][t];
    101     else
    102         return ST[y - (1 << t) + 1][t];
    103 }
    104 
    105 inline int dis(int x, int y) {
    106     return deep[x] + deep[y] - 2 * deep[lca(x, y)];
    107 }
    108 
    109 void get_root(int x, int f) {
    110     siz[x] = 1;
    111     int large = 0;
    112     for(int i = e[x]; i; i = edge[i].nex) {
    113         int y = edge[i].v;
    114         if(y == f || del[y]) {
    115             continue;
    116         }
    117         get_root(y, x);
    118         siz[x] += siz[y];
    119         large = std::max(large, siz[y]);
    120     }
    121     large = std::max(large, _n - siz[x]);
    122     if(large < small) {
    123         small = large;
    124         root = x;
    125     }
    126     return;
    127 }
    128 
    129 void DFS_1(int x, int f, int rt) {
    130     siz[x] = 1;
    131     if(FA[rt]) {
    132         seg::insert(rt + n, d[x], val[x]);
    133     }
    134     d[x] = d[f] + 1;
    135     seg::insert(rt, d[x], val[x]);
    136     //printf("insert %d %d %d 
    ", rt, d[x], val[x]);
    137     for(int i = e[x]; i; i = edge[i].nex) {
    138         int y = edge[i].v;
    139         if(del[y] || y == f) {
    140             continue;
    141         }
    142         DFS_1(y, x, rt);
    143         siz[x] += siz[y];
    144     }
    145     return;
    146 }
    147 
    148 void poi_div(int x, int f) {
    149     small = INF;
    150     get_root(x, 0);
    151     x = root;
    152     FA[x] = f;
    153 
    154     seg::insert(x, 0, val[x]);
    155     if(f) {
    156         seg::insert(x + n, d[x], val[x]);
    157     }
    158     d[x] = 0;
    159     for(int i = e[x]; i; i = edge[i].nex) {
    160         int y = edge[i].v;
    161         if(del[y]) continue;
    162         DFS_1(y, x, x);
    163     }
    164 
    165     del[x] = 1;
    166     for(int i = e[x]; i; i = edge[i].nex) {
    167         int y = edge[i].v;
    168         if(del[y]) {
    169             continue;
    170         }
    171         _n = siz[y];
    172         poi_div(y, x);
    173     }
    174     return;
    175 }
    176 
    177 inline void change(int x, int v) {
    178     /// val[x] = v
    179     int first_x = x;
    180     while(x) {
    181         int t = dis(first_x, x);
    182         seg::insert(x, t, v - val[first_x]);
    183         if(FA[x]) {
    184             seg::insert(x + n, dis(first_x, FA[x]), v - val[first_x]);
    185         }
    186         x = FA[x];
    187     }
    188     val[first_x] = v;
    189     return;
    190 }
    191 
    192 inline int ask(int x, int k) {
    193     int first_x = x, ans = 0;
    194     while(x) {
    195         ans += seg::ask(x, 0, k - dis(x, first_x));
    196         //printf("ans += [%d %d] %d 
    ", 0, k - dis(x, first_x), seg::ask(x, 0, k - dis(x, first_x)));
    197         if(FA[x]) {
    198             ans -= seg::ask(x + n, 0, k - dis(FA[x], first_x));
    199             //printf("ans -= [%d %d] %d 
    ", 0, k - dis(FA[x], first_x), seg::ask(x + n, 0, k - dis(FA[x], first_x)));
    200         }
    201         //printf("%d %d 
    ", x, ans);
    202         x = FA[x];
    203     }
    204     return ans;
    205 }
    206 
    207 int main() {
    208 
    209     int q;
    210     read(n); read(q);
    211     for(int i = 1; i <= n; i++) {
    212         read(val[i]);
    213     }
    214     for(int i = 1, x, y; i < n; i++) {
    215         read(x); read(y);
    216         add(x, y); add(y, x);
    217     }
    218 
    219     DFS_0(1, 0);
    220     prework();
    221     _n = n;
    222     poi_div(1, 0);
    223 
    224     /*for(int i = 1; i <= n; i++) {
    225         printf("FA %d = %d 
    ", i, FA[i]);
    226     }
    227     puts("");*/
    228 
    229     int lastans = 0;
    230     for(int i = 1, f, x, y; i <= q; i++) {
    231         read(f); read(x); read(y);
    232         x ^= lastans; y ^= lastans;
    233         if(f == 0) { /// ask
    234             lastans = ask(x, y);
    235             printf("%d
    ", lastans);
    236         }
    237         else { /// change
    238             change(x, y);
    239         }
    240     }
    241 
    242     return 0;
    243 }
    AC代码

    差0.06s就TLE还行。常数过大引起不适.jpg

    BZOJ4372 烁烁的游戏

    论刷题的作用.....不调1A点分树还行。

    跟上面一题完全倒过来了...修改一个点半径k内的点,询问点权。

    有个很妙的想法是点分树上每个点维护它的点分子树中原树距它为d的点的修改量。查询的时候一路跳上去。

    去重的方法跟上面一样,再开个线段树维护x的点分子树中原树距离FA[x]为d的点的修改量。

      1 #include <cstdio>
      2 #include <algorithm>
      3 
      4 const int N = 100010, INF = 0x3f3f3f3f, M = 20000010;
      5 
      6 inline void read(int &x) {
      7     x = 0;
      8     char c = getchar();
      9     bool f = 0;
     10     while(c < '0' || c > '9') {
     11         if(c == '-') {
     12             f = 1;
     13         }
     14         c = getchar();
     15     }
     16     while(c >= '0' && c <= '9') {
     17         x = (x << 3) + (x << 1) + c - 48;
     18         c = getchar();
     19     }
     20     if(f) {
     21         x = (~x) + 1;
     22     }
     23     return;
     24 }
     25 
     26 struct Edge {
     27     int nex, v;
     28 }edge[N << 1]; int tp;
     29 
     30 int e[N], FA[N], n, num, ST[N << 1][20], pw[N << 1], deep[N], small, root, _n, siz[N], pos[N];
     31 char str[3];
     32 bool del[N];
     33 
     34 inline void add(int x, int y) {
     35     tp++;
     36     edge[tp].v = y;
     37     edge[tp].nex = e[x];
     38     e[x] = tp;
     39     return;
     40 }
     41 
     42 namespace seg {
     43     int tot, tag[M], ls[M], rs[M], rt[N << 1];
     44     inline void pushdown(int o) {
     45         if(tag[o]) {
     46             if(!ls[o]) ls[o] = ++tot;
     47             if(!rs[o]) rs[o] = ++tot;
     48             tag[ls[o]] += tag[o];
     49             tag[rs[o]] += tag[o];
     50             tag[o] = 0;
     51         }
     52         return;
     53     }
     54     void add(int L, int R, int v, int l, int r, int &o) {
     55         if(!o) o = ++tot;
     56         if(L <= l && r <= R) {
     57             tag[o] += v;
     58             return;
     59         }
     60         pushdown(o);
     61         int mid = (l + r) >> 1;
     62         if(L <= mid) {
     63             add(L, R, v, l, mid, ls[o]);
     64         }
     65         if(mid < R) {
     66             add(L, R, v, mid + 1, r, rs[o]);
     67         }
     68         return;
     69     }
     70     int getSum(int p, int l, int r, int o) {
     71         if(!o) return 0;
     72         if(l == r) {
     73             return tag[o];
     74         }
     75         pushdown(o);
     76         int mid = (l + r) >> 1;
     77         if(p <= mid) {
     78             return getSum(p, l, mid, ls[o]);
     79         }
     80         else {
     81             return getSum(p, mid + 1, r, rs[o]);
     82         }
     83     }
     84     inline void insert(int id, int L, int R, int v) {
     85         add(L + 1, R + 1, v, 1, n, rt[id]);
     86         return;
     87     }
     88     inline int ask(int id, int p) {
     89         return getSum(p + 1, 1, n, rt[id]);
     90     }
     91 }
     92 
     93 void DFS_0(int x, int f) {
     94     pos[x] = ++num;
     95     ST[num][0] = x;
     96     deep[x] = deep[f] + 1;
     97     for(int i = e[x]; i; i = edge[i].nex) {
     98         int y = edge[i].v;
     99         if(y == f) continue;
    100         DFS_0(y, x);
    101         ST[++num][0] = x;
    102     }
    103     return;
    104 }
    105 
    106 inline void prework() {
    107     for(int i = 2; i <= num; i++) {
    108         pw[i] = pw[i >> 1] + 1;
    109     }
    110     for(int j = 1; j <= pw[num]; j++) {
    111         for(int i = 1; i + (1 << j) - 1 <= num; i++) {
    112             if(deep[ST[i][j - 1]] < deep[ST[i + (1 << (j - 1))][j - 1]])
    113                 ST[i][j] = ST[i][j - 1];
    114             else
    115                 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
    116         }
    117     }
    118     return;
    119 }
    120 
    121 inline int lca(int x, int y) {
    122     x = pos[x];
    123     y = pos[y];
    124     if(x > y) std::swap(x, y);
    125     int t = pw[y - x + 1];
    126     if(deep[ST[x][t]] < deep[ST[y - (1 << t) + 1][t]])
    127         return ST[x][t];
    128     else
    129         return ST[y - (1 << t) + 1][t];
    130 }
    131 
    132 inline int dis(int x, int y) {
    133     return deep[x] + deep[y] - 2 * deep[lca(x, y)];
    134 }
    135 
    136 void get_root(int x, int f) {
    137     siz[x] = 1;
    138     int large = 0;
    139     for(int i = e[x]; i; i = edge[i].nex) {
    140         int y = edge[i].v;
    141         if(del[y] || y == f) continue;
    142         get_root(y, x);
    143         siz[x] += siz[y];
    144         large = std::max(large, siz[y]);
    145     }
    146     large = std::max(large, _n - siz[x]);
    147     if(small > large) {
    148         small = large;
    149         root = x;
    150     }
    151     return;
    152 }
    153 
    154 void DFS_1(int x, int f, int rt) {
    155     siz[x] = 1;
    156     for(int i = e[x]; i; i = edge[i].nex) {
    157         int y = edge[i].v;
    158         if(del[y] || y == f) {
    159             continue;
    160         }
    161         DFS_1(y, x, rt);
    162         siz[x] += siz[y];
    163     }
    164     return;
    165 }
    166 
    167 void poi_div(int x, int f) {
    168     small = INF;
    169     get_root(x, 0);
    170     x = root;
    171     FA[x] = f;
    172 
    173     for(int i = e[x]; i; i = edge[i].nex) {
    174         int y = edge[i].v;
    175         if(del[y]) continue;
    176         DFS_1(y, x, x);
    177     }
    178 
    179     del[x] = 1;
    180     for(int i = e[x]; i; i = edge[i].nex) {
    181         int y = edge[i].v;
    182         if(del[y]) continue;
    183         _n = siz[y];
    184         poi_div(y, x);
    185     }
    186 
    187     return;
    188 }
    189 
    190 inline void change(int x, int d, int v) {
    191     int first_x = x;
    192     while(x) {
    193         int t = dis(x, first_x);
    194         if(t <= d) {
    195             seg::insert(x, 0, d - t, v);
    196         }
    197         if(FA[x]) {
    198             t = dis(FA[x], first_x);
    199             if(t <= d) {
    200                 seg::insert(x + n, 0, d - t, v);
    201             }
    202         }
    203         x = FA[x];
    204     }
    205     return;
    206 }
    207 
    208 inline int ask(int x) {
    209     int ans = 0, fisrt_x = x;
    210     while(x) {
    211         ans += seg::ask(x, dis(x, fisrt_x));
    212         if(FA[x]) {
    213             ans -= seg::ask(x + n, dis(FA[x], fisrt_x));
    214         }
    215         x = FA[x];
    216     }
    217     return ans;
    218 }
    219 
    220 int main() {
    221 
    222     int q;
    223     read(n); read(q);
    224     for(int i = 1, x, y; i < n; i++) {
    225         read(x); read(y);
    226         add(x, y); add(y, x);
    227     }
    228 
    229     DFS_0(1, 0);
    230     prework();
    231     _n = n;
    232     poi_div(1, 0);
    233 
    234 
    235     for(int i = 1, x, y, z; i <= q; i++) {
    236         scanf("%s", str);
    237         if(str[0] == 'Q') {
    238             read(x);
    239             int t = ask(x);
    240             printf("%d
    ", t);
    241         }
    242         else {
    243             read(x); read(y); read(z);
    244             change(x, y, z);
    245         }
    246     }
    247 
    248     return 0;
    249 }
    AC代码

    常数大伤不起啊...开了快读还差点T(或许是bzoj太慢?)

    LOJ#6145 Easy

    跟开店类似但是简单一些...(指点分树做法),然后我又1A了.......

    求编号在[l, r]中的点到x的最短距离。

    根据套路,我们考虑怎么统计答案:点分树上每个点维护它的点分子树中每个点到它的距离(这种信息是O(nlogn)的),要求区间取min。然后查询的时候跳父亲统计答案就行了。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 
      5 const int N = 100010, INF = 0x3f3f3f3f, M = 25000010;
      6 
      7 struct Edge {
      8     int nex, v, len;
      9 }edge[N << 1]; int tp;
     10 
     11 int e[N], FA[N], siz[N], n, _n, root, small, lm, pos[N], ST[N << 1][20], num, pw[N << 1], deep[N], dist[N], d[N];
     12 bool del[N];
     13 
     14 inline void add(int x, int y, int z) {
     15     tp++;
     16     edge[tp].v = y;
     17     edge[tp].len = z;
     18     edge[tp].nex = e[x];
     19     e[x] = tp;
     20     return;
     21 }
     22 
     23 namespace seg {
     24     int tot, small[M], ls[M], rs[M], rt[N];
     25     inline void init() {
     26         memset(small, 0x3f, sizeof(small));
     27         return;
     28     }
     29     void add(int p, int v, int l, int r, int &o) {
     30         if(!o) {
     31             o = ++tot;
     32         }
     33         if(l == r) {
     34             small[o] = std::min(small[o], v);
     35             return;
     36         }
     37         int mid = (l + r) >> 1;
     38         if(p <= mid) {
     39             add(p, v, l, mid, ls[o]);
     40         }
     41         else {
     42             add(p, v, mid + 1, r, rs[o]);
     43         }
     44         small[o] = std::min(small[ls[o]], small[rs[o]]);
     45         return;
     46     }
     47     int getMin(int L, int R, int l, int r, int o) {
     48         //printf("%d %d %d %d %d 
    ", L, R, l, r, o);
     49         if(!o) return INF;
     50         if(L <= l && r <= R) {
     51             return small[o];
     52         }
     53         int mid = (l + r) >> 1, ans = INF;
     54         if(L <= mid) {
     55             ans = std::min(ans, getMin(L, R, l, mid, ls[o]));
     56         }
     57         if(mid < R) {
     58             ans = std::min(ans, getMin(L, R, mid + 1, r, rs[o]));
     59         }
     60         return ans;
     61     }
     62     inline void insert(int id, int p, int v) {
     63         //printf("insert : %d %d %d 
    ", id, p, v);
     64         add(p, v, 1, n, rt[id]);
     65         return;
     66     }
     67     inline int ask(int id, int l, int r) {
     68         return getMin(l, r, 1, n, rt[id]);
     69     }
     70 }
     71 
     72 void DFS_0(int x, int f) {
     73     deep[x] = deep[f] + 1;
     74     pos[x] = ++num;
     75     ST[num][0] = x;
     76     for(int i = e[x]; i; i = edge[i].nex) {
     77         int y = edge[i].v;
     78         if(y == f) continue;
     79         dist[y] = dist[x] + edge[i].len;
     80         DFS_0(y, x);
     81         ST[++num][0] = x;
     82     }
     83     return;
     84 }
     85 
     86 inline void prework() {
     87     for(int i = 2; i <= num; i++) {
     88         pw[i] = pw[i >> 1] + 1;
     89     }
     90     for(int j = 1; j <= pw[num]; j++) {
     91         for(int i = 1; i + (1 << j) - 1 <= num; i++) {
     92             if(deep[ST[i][j - 1]] < deep[ST[i + (1 << (j - 1))][j - 1]])
     93                 ST[i][j] = ST[i][j - 1];
     94             else
     95                 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
     96         }
     97     }
     98     return;
     99 }
    100 
    101 inline int lca(int x, int y) {
    102     x = pos[x];
    103     y = pos[y];
    104     if(x > y) std::swap(x, y);
    105     int t = pw[y - x + 1];
    106     if(deep[ST[x][t]] < deep[ST[y - (1 << t) +1][t]])
    107         return ST[x][t];
    108     else
    109         return ST[y - (1 << t) + 1][t];
    110 }
    111 
    112 inline int dis(int x, int y) {
    113     return dist[x] + dist[y] - 2 * dist[lca(x, y)];
    114 }
    115 
    116 void get_root(int x, int f) {
    117     siz[x] = 1;
    118     int large = 0;
    119     for(int i = e[x]; i; i = edge[i].nex) {
    120         int y = edge[i].v;
    121         if(del[y] || y == f) continue;
    122         get_root(y, x);
    123         large = std::max(large, siz[y]);
    124         siz[x] += siz[y];
    125     }
    126     large = std::max(large, _n - siz[x]);
    127     if(small > large) {
    128         small = large;
    129         root = x;
    130     }
    131     return;
    132 }
    133 
    134 void DFS_1(int x, int f, int rt) {
    135     siz[x] = 1;
    136     seg::insert(rt, x, d[x]);
    137     for(int i = e[x]; i; i = edge[i].nex) {
    138         int y = edge[i].v;
    139         if(del[y] || y == f) continue;
    140         d[y] = d[x] + edge[i].len;
    141         DFS_1(y, x, rt);
    142         siz[x] += siz[y];
    143     }
    144     return;
    145 }
    146 
    147 void poi_div(int x, int f) {
    148     small = INF;
    149     get_root(x, 0);
    150     x = root;
    151     FA[x] = f;
    152 
    153     seg::insert(x, x, 0);
    154     for(int i = e[x]; i; i = edge[i].nex) {
    155         int y = edge[i].v;
    156         if(del[y]) continue;
    157         d[y] = edge[i].len;
    158         DFS_1(y, x, x);
    159     }
    160 
    161     del[x] = 1;
    162     for(int i = e[x]; i; i = edge[i].nex) {
    163         int y = edge[i].v;
    164         if(del[y]) continue;
    165         _n = siz[y];
    166         poi_div(y, x);
    167     }
    168    return;
    169 }
    170 
    171 inline int ask(int x, int L, int R) {
    172     int first_x = x, ans = INF;
    173     while(x) {
    174         ans = std::min(ans, seg::ask(x, L, R) + dis(x, first_x));
    175         //printf("%d + %d 
    ", seg::ask(x, L, R), dis(x, first_x));
    176         x = FA[x];
    177     }
    178     return ans;
    179 }
    180 
    181 int main() {
    182     scanf("%d", &n);
    183     for(int i = 1, x, y, z; i < n; i++) {
    184         scanf("%d%d%d", &x, &y, &z);
    185         add(x, y, z); add(y, x, z);
    186         lm += z;
    187     }
    188 
    189     DFS_0(1, 0);
    190     prework();
    191     seg::init();
    192     _n = n;
    193     poi_div(1, 0);
    194 
    195     int q;
    196     scanf("%d", &q);
    197     for(int i = 1, l, r, x; i <= n; i++) {
    198         scanf("%d%d%d", &l, &r, &x);
    199         int t = ask(x, l, r);
    200         printf("%d
    ", t);
    201     }
    202 
    203     return 0;
    204 }
    AC代码

    洛谷P3920 紫荆花之恋

    这个......卡常神题 + 码农神题。11.2k,500行还行。

    一开始写的妃萱treap飞旋只有55分,换成splay有80分了,但是链的部分还是过不去。最后数据分治了一下终于A了......

    动态加点,求树上dis(x, y) <= w[i] + w[j]的点对数量。

    链的部分数据就直接用4棵平衡树,维护一下两边对两边分别的贡献即可。

    考虑现在有个点分树,然后我们在原树和点分树下同时插入一个叶子。

    推个式子,往上跳的时候统计一下答案,记得把FA[x]多算的答案减去,点分树经典套路了。

    如果发现某一层的点分树子树过大,就暴力重构该子树,建出完全平衡点分子树。

      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <algorithm>
      4 #include <climits>
      5 
      6 typedef long long LL;
      7 const int N = 100010, M = 20000010, INF = 0x7f7f7f7f, MO = 1e9;
      8 const double alpha = 0.8;
      9 
     10 inline void read(int &x) {
     11     x = 0;
     12     char c = getchar();
     13     while(c < '0' || c > '9') {
     14         c = getchar();
     15     }
     16     while(c >= '0' && c <= '9') {
     17         x = (x << 3) + (x << 1) + c - 48;
     18         c = getchar();
     19     }
     20     return;
     21 }
     22 
     23 struct Edge {
     24     int nex, v, len, pre;
     25 }edge[N << 1], EDGE[N << 1]; int tp, TP;
     26 
     27 int e[N], E[N], FA[N], fa[N][20], dist[N], n, root, _n, small, w[N], SIZ[N], rebuild;
     28 int Time, ine[N], d[N], deep[N], pw[N], vis[N], siz[N], stkEDGE[N << 1], TOP, Cnt, ROOT;
     29 LL ANS;
     30 bool del[N];
     31 
     32 namespace tree {
     33     int tot, val[M], cnt[M], s[M][2], fa[M], siz[M], rt[N << 1], turn;
     34     int stk[M], top;
     35     inline int np(int v, int f) {
     36         int x;
     37         if(top) {
     38             x = stk[top];
     39             top--;
     40         }
     41         else {
     42             x = ++tot;
     43         }
     44         cnt[x] = siz[x] = 1;
     45         s[x][0] = s[x][1] = 0;
     46         fa[x] = f;
     47         val[x] = v;
     48         return x;
     49     }
     50     inline void pushup(int x) {
     51         siz[x] = siz[s[x][0]] + siz[s[x][1]] + cnt[x];
     52         if(!fa[x]) rt[turn] = x;
     53         return;
     54     }
     55     inline void rotate(int x) {
     56         int y = fa[x];
     57         int z = fa[y];
     58         bool f = (s[y][1] == x);
     59 
     60         fa[x] = z;
     61         if(z) s[z][s[z][1] == y] = x;
     62         s[y][f] = s[x][!f];
     63         if(s[x][!f]) fa[s[x][!f]] = y;
     64         s[x][!f] = y;
     65         fa[y] = x;
     66 
     67         pushup(y);
     68         return;
     69     }
     70     inline void splay(int x, int g = 0) {
     71         int y = fa[x];
     72         int z = fa[y];
     73         while(y != g) {
     74             if(z != g) {
     75                 (s[z][1] == y) ^ (s[y][1] == x) ?
     76                 rotate(x) : rotate(y);
     77             }
     78             rotate(x);
     79             y = fa[x];
     80             z = fa[y];
     81         }
     82         pushup(x);
     83         return;
     84     }
     85     inline void add(int id, int v) {
     86         turn = id;
     87         int p = rt[turn];
     88         if(!p) {
     89             rt[turn] = np(v, 0);
     90             return;
     91         }
     92         while(1) {
     93             siz[p]++;
     94             if(val[p] == v) {
     95                 cnt[p]++;
     96                 break;
     97             }
     98             if(v < val[p] && s[p][0]) {
     99                 p = s[p][0];
    100             }
    101             else if(val[p] < v && s[p][1]) {
    102                 p = s[p][1];
    103             }
    104             else { /// insert node
    105                 bool f = (val[p] < v);
    106                 s[p][f] = np(v, p);
    107                 p = s[p][f];
    108                 break;
    109             }
    110         }
    111         splay(p);
    112         return;
    113     }
    114     inline int getPbyV(int v) {
    115         int p = rt[turn];
    116         while(1) {
    117             if(val[p] == v) break;
    118             if(v < val[p] && s[p][0]) p = s[p][0];
    119             else if(val[p] < v && s[p][1]) p = s[p][1];
    120             else break;
    121         }
    122         splay(p);
    123         return p;
    124     }
    125     inline int ask(int id, int v) {
    126        turn = id;
    127        if(!rt[turn]) return 0;
    128        int p = getPbyV(v);
    129        if(val[p] <= v) return siz[s[p][0]] + cnt[p];
    130        else return siz[s[p][0]];
    131     }
    132     void dfs(int x) {
    133         if(s[x][0]) dfs(s[x][0]);
    134         if(s[x][1]) dfs(s[x][1]);
    135         stk[++top] = x;
    136         return;
    137     }
    138     inline void del(int id) {
    139         turn = id;
    140         if(!rt[turn]) return;
    141         dfs(rt[turn]);
    142         rt[turn] = 0;
    143         return;
    144     }
    145 }
    146 
    147 namespace tree2 {
    148     int tot, ls[M], rs[M], val[M], stk[M], rd[M], siz[M], top, rt[N << 1];
    149     int np(int v) {
    150         int o;
    151         if(top) {
    152             o = stk[top];
    153             top--;
    154         }
    155         else {
    156             o = ++tot;
    157         }
    158         val[o] = v;
    159         rd[o] = (rand() * (1ll << 16) + rand()) % LONG_MAX;
    160         siz[o] = 1;
    161         ls[o] = rs[o] = 0;
    162         return o;
    163     }
    164     int merge(int x, int y) {
    165         if(!x || !y) return x | y;
    166         if(rd[x] >= rd[y]) {
    167             rs[x] = merge(rs[x], y);
    168             siz[x] = siz[ls[x]] + siz[rs[x]] + 1;
    169             return x;
    170         }
    171         else {
    172             ls[y] = merge(x, ls[y]);
    173             siz[y] = siz[ls[y]] + siz[rs[y]] + 1;
    174             return y;
    175         }
    176     }
    177     void splitV(int o, int k, int &x, int &y) {
    178         if(!o) {
    179             x = y = 0;
    180             return;
    181         }
    182         if(val[o] <= k) {
    183             x = o;
    184             splitV(rs[x], k, rs[x], y);
    185         }
    186         else {
    187             y = o;
    188             splitV(ls[y], k, x, ls[y]);
    189         }
    190         siz[o] = siz[ls[o]] + siz[rs[o]] + 1;
    191         return;
    192     }
    193     inline void add(int id, int v) {
    194         int x, y;
    195         splitV(rt[id], v, x, y);
    196         rt[id] = merge(merge(x, np(v)), y);
    197         return;
    198     }
    199     inline int ask(int id, int v) {
    200        int x, y;
    201        splitV(rt[id], v, x, y);
    202        int ans = siz[x];
    203        rt[id] = merge(x, y);
    204        return ans;
    205     }
    206     void dfs(int x) {
    207         if(ls[x]) dfs(ls[x]);
    208         if(rs[x]) dfs(rs[x]);
    209         stk[++top] = x;
    210         return;
    211     }
    212     inline void del(int id) {
    213         if(rt[id]) {
    214             dfs(rt[id]);
    215             rt[id] = 0;
    216         }
    217         return;
    218     }
    219 }
    220 
    221 void out(int x) {
    222     printf("x = %d 
    ", x);
    223     for(int i = E[x]; i; i = EDGE[i].nex) {
    224         int y = EDGE[i].v;
    225         printf("  x = %d y = %d  in_E_check %d
    ", x, y, ine[y] == i);
    226         out(y);
    227     }
    228     return;
    229 }
    230 
    231 inline void add(int x, int y, int z) {
    232     tp++;
    233     edge[tp].v = y;
    234     edge[tp].len = z;
    235     edge[tp].nex = e[x];
    236     edge[e[x]].pre = tp;
    237     e[x] = tp;
    238     return;
    239 }
    240 
    241 inline void ADD(int x, int y) {
    242     int o;
    243     if(TOP) {
    244         o = stkEDGE[TOP];
    245         TOP--;
    246     }
    247     else {
    248         o = ++TP;
    249     }
    250     EDGE[o].v = y;
    251     EDGE[o].nex = E[x];
    252     EDGE[o].pre = 0;
    253     EDGE[E[x]].pre = o;
    254     E[x] = o;
    255     ine[y] = o;
    256     return;
    257 }
    258 
    259 inline void delPoi(int x) {
    260     for(register int i = E[x]; i; i = EDGE[i].nex) {
    261         stkEDGE[++TOP] = i;
    262     }
    263     E[x] = 0;
    264     return;
    265 }
    266 
    267 inline void delEDGE(int i, int x) {
    268     if(!EDGE[i].pre && !EDGE[i].nex) {
    269         E[x] = 0;
    270         return;
    271     }
    272     if(!EDGE[i].pre) {
    273         E[x] = EDGE[i].nex;
    274         EDGE[EDGE[i].nex].pre = 0;
    275         return;
    276     }
    277     if(!EDGE[i].nex) {
    278         EDGE[EDGE[i].pre].nex = 0;
    279         return;
    280     }
    281     EDGE[EDGE[i].pre].nex = EDGE[i].nex;
    282     EDGE[EDGE[i].nex].pre = EDGE[i].pre;
    283     stkEDGE[++TOP] = i;
    284     return;
    285 }
    286 
    287 inline int lca(int x, int y) {
    288     if(deep[x] > deep[y]) std::swap(x, y);
    289     int t = pw[n];
    290     while(t >= 0 && deep[x] < deep[y]) {
    291         if(deep[fa[y][t]] >= deep[x]) {
    292             y = fa[y][t];
    293         }
    294         t--;
    295     }
    296     if(x == y) return x;
    297     t = pw[n];
    298     while(t >= 0 && fa[x][0] != fa[y][0]) {
    299         if(fa[x][t] != fa[y][t]) {
    300             x = fa[x][t];
    301             y = fa[y][t];
    302         }
    303         t--;
    304     }
    305     return fa[x][0];
    306 }
    307 
    308 inline int dis(int x, int y) {
    309     return dist[x] - 2 * dist[lca(x, y)] + dist[y];
    310 }
    311 
    312 void DFS_0(int x) {
    313     vis[x] = Time;
    314     del[x] = 0;
    315     tree::del(x);
    316     tree::del(x + n);
    317     Cnt++;
    318     for(register int i = E[x]; i; i = EDGE[i].nex) {
    319         int y = EDGE[i].v;
    320         DFS_0(y);
    321     }
    322     delPoi(x);
    323     return;
    324 }
    325 
    326 void get_root(int x, int f) {
    327     siz[x] = 1;
    328     int large = 0;
    329     for(register int i = e[x]; i; i = edge[i].nex) {
    330         int y = edge[i].v;
    331         if(del[y] || y == f || vis[y] != Time) {
    332             continue;
    333         }
    334         get_root(y, x);
    335         siz[x] += siz[y];
    336         large = std::max(large, siz[y]);
    337     }
    338     large = std::max(large, _n - siz[x]);
    339     if(small > large) {
    340         small = large;
    341         root = x;
    342     }
    343     return;
    344 }
    345 
    346 void DFS_1(int x, int f, int rt) {
    347     siz[x] = 1;
    348     tree::add(rt, d[x] - w[x]);
    349     if(FA[rt]) {
    350         tree::add(rt + n, dis(x, FA[rt]) - w[x]);
    351     }
    352     for(register int i = e[x]; i; i = edge[i].nex) {
    353         int y = edge[i].v;
    354         if(del[y] || vis[y] != Time || y == f) {
    355             continue;
    356         }
    357         d[y] = d[x] + edge[i].len;
    358         DFS_1(y, x, rt);
    359         siz[x] += siz[y];
    360     }
    361     return;
    362 }
    363 
    364 void poi_div(int x, int f) {
    365     small = INF;
    366     get_root(x, 0);
    367     x = root;
    368     FA[x] = f;
    369     if(!f) ROOT = x;
    370     ADD(f, x);
    371 
    372     SIZ[x] = 1;
    373     tree::add(x, -w[x]);
    374     if(f) {
    375         tree::add(x + n, dis(x, f) - w[x]);
    376     }
    377     for(register int i = e[x]; i; i = edge[i].nex) {
    378         int y = edge[i].v;
    379         if(del[y] || vis[y] != Time) {
    380             continue;
    381         }
    382         d[y] = edge[i].len;
    383         DFS_1(y, x, x);
    384         SIZ[x] += siz[y];
    385     }
    386 
    387     del[x] = 1;
    388     for(register int i = e[x]; i; i = edge[i].nex) {
    389         int y = edge[i].v;
    390         if(del[y] || vis[y] != Time) {
    391             continue;
    392         }
    393         _n = siz[y];
    394         poi_div(y, x);
    395     }
    396     return;
    397 }
    398 
    399 inline void solve(int x) {
    400     Time++;
    401     Cnt = 0;
    402     DFS_0(x); /// get point to rebuild
    403     if(FA[x]) {
    404         delEDGE(ine[x], FA[x]);
    405     }
    406     _n = Cnt;
    407     poi_div(x, FA[x]);
    408     return;
    409 }
    410 
    411 inline void insert(int x, int f, int d) {
    412     if(!f) {
    413         SIZ[x] = 1;
    414         deep[x] = 1;
    415         ROOT = 1;
    416         tree::add(x, -w[x]);
    417         return;
    418     }
    419 
    420     fa[x][0] = f;
    421     for(register int j = 1; j <= pw[x]; j++) {
    422         fa[x][j] = fa[fa[x][j - 1]][j - 1];
    423     }
    424     dist[x] = dist[f] + d;
    425     deep[x] = deep[f] + 1;
    426     add(x, f, d); add(f, x, d);
    427 
    428     FA[x] = f;
    429     ADD(f, x);
    430 
    431     f = x;
    432     while(f) {
    433         SIZ[f]++;
    434         int temp = dis(x, f) - w[x];
    435         ANS += tree::ask(f, -temp); /// how many not larger than v
    436         if(FA[f]) {
    437             int t2 = dis(FA[f], x) - w[x];
    438             ANS -= tree::ask(f + n, -t2); /// the repeat count
    439             tree::add(f + n, t2);
    440         }
    441         tree::add(f, temp);
    442         if(FA[f] && SIZ[f] > (SIZ[FA[f]] + 1) * alpha) {
    443             rebuild = FA[f];
    444         }
    445         f = FA[f];
    446     }
    447 
    448     if(rebuild) {
    449         solve(rebuild);
    450         rebuild = 0;
    451     }
    452     return;
    453 }
    454 
    455 #define Left 1
    456 #define Right 2
    457 namespace line {
    458     int dir[N], F;
    459     inline void insert(int x, int f, int d) {
    460         if(!f) {
    461             return;
    462         }
    463         if(dir[f]) dir[x] = dir[f];
    464         else {
    465             if(x == 2) dir[x] = Left;
    466             else dir[x] = Right;
    467         }
    468         dist[x] = dist[f] + d;
    469         ANS += tree::ask(dir[x], w[x] - dist[x]);
    470         tree::add(3 - dir[x], dist[x] - w[x]);
    471         ANS += tree::ask(dir[x] + 2, w[x] - dist[x]);
    472         tree::add(dir[x] + 2, -w[x] - dist[x]);
    473         if(dist[x] <= w[x] + w[1]) ANS++;
    474         return;
    475     }
    476 }
    477 #undef Left
    478 #undef Right
    479 
    480 int main() {
    481 
    482     read(n);
    483     bool F = n >= 5 && n <= 8;
    484     read(n);
    485     for(register int i = 2; i <= n; i++)
    486         pw[i] = pw[i >> 1] + 1;
    487     int x, y;
    488     for(register int i = 1; i <= n; i++) {
    489         read(x); read(y); read(w[i]);
    490         x ^= (ANS % MO);
    491         F ? line::insert(i, x, y) : insert(i, x, y);
    492         printf("%lld
    ", ANS);
    493     }
    494     return 0;
    495 }
    AC代码

    开店留着复习用。

  • 相关阅读:
    vc生产垃圾清理
    完整的.h宏定义
    vs 2017 boost 安装目录 非安装
    cdlinux
    TryEnterCriticalSection
    go get 升级所有
    delphi win7 and high path
    本机激活Qemu网络配置 之桥接 win 10 2019 LTSC
    archlinux alsa安装,音量设置和音量信息保存
    windows搭建gcc开发环境(msys2) objdump
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10426796.html
Copyright © 2011-2022 走看看