[ZJOI2016]大森林

(貌似整个代码不能用 $makeroot$ ?是因为是有根树?)

因为是区间操作,所以可以考虑在区间内与区间外的差异

对于操作 $1$ ,可以看作一个生成节点包含了到下一个 $1$ 操作之间长出的节点,那么对于一个操作 $l, r$ ,相当于是在 $l$ 处将当前生成节点及其包含的节点整个移植到它更改后的位置,到 $r + 1$ 时再移植回去,所以可以考虑将一个 $1$ 操作分解为两个操作(一个移植,一个移植回去),故可以将所有操作按端点、时间排序(以及同位置修改操作必定在查询操作前,因为可以先把树建完再查询对结果没有影响),扫描一遍即可

同时,为了方便移植,将每个生成节点看作新建的一个虚点

对于操作 $0$ ,直接在虚点下 $link$ 即可,因为就算已经建了一些对于当前操作不存在的虚点,也不会对答案造成影响

对于操作 $2$ ,无法正面在 $LCT$ 上算出两点的距离,故可考虑查分,得到 $Ans = Sum_x + Sum_y - 2 * Sum_{lca}$ ,其中实点贡献为 $1$ ,虚点贡献为 $0$

对于求 $LCA$ ,先 $access (y)$ ,再在 $access (x)$ 的时候得到的最后一个跳虚边的点即是它们的 $LCA$

代码

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 
  6 using namespace std;
  7 
  8 const int MAXN = 3e05 + 10;
  9 
 10 struct QuerySt {
 11     int pos, time;
 12     int x, y;
 13 
 14     QuerySt () {}
 15     QuerySt (int fpos, int ftime, int fx, int fy) :
 16         pos (fpos), time (ftime), x (fx), y (fy) {}
 17 
 18     bool operator < (const QuerySt& p) const {
 19         return pos == p.pos ? time < p.time : pos < p.pos;
 20     }
 21 } ;
 22 QuerySt Query[MAXN];
 23 int que = 0;
 24 
 25 int N, M;
 26 
 27 int father[MAXN]= {0};
 28 int son[MAXN][2]= {0};
 29 int Sum[MAXN]= {0}, value[MAXN]= {0};
 30 
 31 int isroot (int p) {
 32     return son[father[p]][0] != p && son[father[p]][1] != p;
 33 }
 34 int sonbel (int p) {
 35     return son[father[p]][1] == p;
 36 }
 37 void pushup (int p) {
 38     Sum[p] = Sum[son[p][0]] + Sum[son[p][1]] + value[p];
 39 }
 40 void rotate (int p) {
 41     int fa = father[p], anc = father[fa];
 42     int s = sonbel (p);
 43     son[fa][s] = son[p][s ^ 1];
 44     if (son[fa][s])
 45         father[son[fa][s]] = fa;
 46     if (! isroot (fa))
 47         son[anc][sonbel (fa)] = p;
 48     father[p] = anc;
 49     son[p][s ^ 1] = fa, father[fa] = p;
 50     pushup (fa), pushup (p);
 51 }
 52 void splay (int p) {
 53     for (int fa = father[p]; ! isroot (p); rotate (p), fa = father[p])
 54         if (! isroot (fa))
 55             sonbel (p) == sonbel (fa) ? rotate (fa) : rotate (p);
 56 }
 57 int Access (int p) {
 58     int tp = 0;
 59     for ( ; p; tp = p, p = father[p])
 60         splay (p), son[p][1] = tp, pushup (p);
 61     return tp;
 62 }
 63 void link (int x, int y) { // 注意此时没有makeroot所以需要注意是将y连到x下
 64     splay (y);
 65     father[y] = x;
 66 }
 67 void cut (int x) {
 68     Access (x), splay (x);
 69     father[son[x][0]] = 0, son[x][0] = 0;
 70     pushup (x);
 71 }
 72 
 73 int totq = 0;
 74 int ans[MAXN]= {0};
 75 void Solve () {
 76     sort (Query + 1, Query + que + 1);
 77     for (int i = 1; i <= que; i ++) {
 78         int time = Query[i].time;
 79         int x = Query[i].x, y = Query[i].y;
 80         if (time > 0) {
 81             Access (x), splay (x), ans[time] += Sum[x];
 82             int lca = Access (y);
 83             splay (y), ans[time] += Sum[y];
 84             Access (lca), splay (lca), ans[time] -= (Sum[lca] << 1);
 85         }
 86         else
 87             cut (x), link (y, x);
 88     }
 89 }
 90 
 91 int getnum () {
 92     int num = 0;
 93     char ch = getchar ();
 94 
 95     while (! isdigit (ch))
 96         ch = getchar ();
 97     while (isdigit (ch))
 98         num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
 99 
100     return num;
101 }
102 
103 int ind[MAXN]= {0};
104 int liml[MAXN], limr[MAXN];
105 int nodes = 1;
106 int main () {
107     N = getnum (), M = getnum ();
108     int lastr = 1, real = 1;
109     ind[1] = Sum[1] = value[1] = 1, liml[1] = 1, limr[1] = N;
110     link (1, nodes = lastr = 2);
111     for (int i = 1; i <= M; i ++) {
112         int opt = getnum ();
113         if (opt == 0) {
114             int l = getnum (), r = getnum ();
115             link (lastr, ind[++ real] = ++ nodes);
116             value[nodes] = Sum[nodes] = 1;
117             liml[real] = l, limr[real] = r;
118         }
119         else if (opt == 1) {
120             int l = getnum (), r = getnum (), x = getnum ();
121             l = max (l, liml[x]), r = min (r, limr[x]);
122             if (l > r)
123                 continue;
124             link (lastr, ++ nodes);
125             Query[++ que] = QuerySt (l, i - M, nodes, ind[x]); // 由nodes离开link向index[x]
126             Query[++ que] = QuerySt (r + 1, i - M, nodes, lastr);
127             lastr = nodes;
128         }
129         else if (opt == 2) {
130             int x = getnum (), u = getnum (), v = getnum ();
131             Query[++ que] = QuerySt (x, ++ totq, ind[u], ind[v]); // 由index[u]到index[v]的距离
132         }
133     }
134     Solve ();
135     for (int i = 1; i <= totq; i ++)
136         printf ("%d\n", ans[i]);
137 
138     return 0;
139 }
140 
141 /*
142 5 5
143 0 1 5
144 1 2 4 2
145 0 1 4
146 2 1 1 3
147 2 2 1 3
148 */

猜你喜欢

转载自www.cnblogs.com/Colythme/p/10179977.html
今日推荐