BZOJ 1969 航线规划 - LCT 维护边双联通分量

Solution

实际上就是查询 $u$ 到 $v$ 路径上 边双的个数 $ -1$。

并且题目仅有删边, 那么就离线倒序添边。

维护 边双 略有不同: 

首先需要一个并查集, 记录 边双内的点。 在 添加边$(u,v)$时 , 若$u, v$ 已经相连, 那么把 $u, v$ 路径上的点 缩成一个点, 用最上面的点 来代替。

BZOJ 1969 航线规划 - LCT 维护边双联通分量
1 void del(int x, int y) {
2         if (!x) return;
3         fa[x] = y;
4         del(lc(x), y);
5         del(rc(x), y);
6     }
压缩点

 

access 也应该变化 : $f[x]$ 可能已经经过压缩了。

BZOJ 1969 航线规划 - LCT 维护边双联通分量
1 void access(int x) {
2         for (int y = 0; x; y = x, x = f[y] = anc(f[x]))
3             splay(x), ch[x][1] = y, up(x);
4     }
access

 

Code

BZOJ 1969 航线规划 - LCT 维护边双联通分量
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define rd read()
  5 using namespace std;
  6 
  7 const int N = 3e4 + 5;
  8 const int M = 1e5 + 5;
  9 
 10 int n, m;
 11 int fa[N], ans[N], vis[M];
 12 
 13 struct edge {
 14     int u, v;
 15 
 16     bool operator < (const edge &b) const {
 17         return u == b.u ? v < b.v : u < b.u;
 18     }
 19 }e[M];
 20 
 21 struct que {
 22     int op, u, v;
 23 }q[M];
 24 
 25 int read() {
 26     int X = 0, p = 1; char c = getchar();
 27     for (; c > 9 || c < 0; c = getchar())
 28         if (c == -) p = -1;
 29     for (; c >= 0 && c <= 9; c = getchar())
 30         X = X * 10 + c - 0;
 31     return X * p;
 32 }
 33 
 34 int anc(int x) {
 35     return fa[x] == x? x : fa[x] = anc(fa[x]);
 36 }
 37 
 38 namespace LCT {
 39     int f[N], sz[N], ch[N][2], tun[N];
 40 #define lc(x) ch[x][0]
 41 #define rc(x) ch[x][1]
 42 
 43     int isroot(int x) {
 44         return rc(f[x]) != x && lc(f[x]) != x;
 45     }
 46 
 47     int get(int x) {
 48         return rc(f[x]) == x;
 49     }
 50 
 51     void rev(int x) {
 52         swap(lc(x), rc(x));
 53         tun[x] ^= 1;
 54     }
 55 
 56     void up(int x) {
 57         sz[x] = 1;
 58         if (lc(x)) sz[x] += sz[lc(x)];
 59         if (rc(x)) sz[x] += sz[rc(x)];
 60     }
 61 
 62     void pushdown(int x) {
 63         if (tun[x]) {
 64             if (lc(x)) rev(lc(x));
 65             if (rc(x)) rev(rc(x));
 66             tun[x] = 0;
 67         }
 68     }
 69 
 70     void pd(int x) {
 71         if (!isroot(x))
 72             pd(f[x]);
 73         pushdown(x);
 74     }
 75 
 76     void rotate(int x) {
 77         int old = f[x], oldf = f[old], son = ch[x][get(x) ^ 1];
 78         if (!isroot(old)) ch[oldf][get(old)] = x;
 79         ch[x][get(x) ^ 1] = old;
 80         ch[old][get(x)] = son;
 81         f[son] = old; f[x] = oldf; f[old] = x;
 82         up(old); up(x);
 83     }
 84 
 85     void splay(int x) {
 86         pd(x);
 87         for (; !isroot(x); rotate(x))
 88             if (!isroot(f[x]))
 89                 rotate(get(f[x]) == get(x) ? f[x] : x);
 90     }
 91     
 92     void access(int x) {
 93         for (int y = 0; x; y = x, x = f[y] = anc(f[x]))
 94             splay(x), ch[x][1] = y, up(x);
 95     }
 96 
 97     int findr(int x) {
 98         access(x); splay(x);
 99         while (lc(x)) pushdown(x), x = lc(x);
100         return x;
101     }
102 
103     void mroot(int x) {
104         access(x); splay(x); rev(x);
105     }
106 
107     void split(int x, int y) {
108         mroot(x); access(y); splay(y);
109     }
110 
111     void del(int x, int y) {
112         if (!x) return;
113         fa[x] = y;
114         del(lc(x), y);
115         del(rc(x), y);
116     }
117 
118     void link(int x, int y) {
119         mroot(x);
120         f[x] = y;
121     }
122 
123     void merge(int x, int y) {
124         x = anc(x); y = anc(y);
125         if (x == y)
126             return;
127         mroot(x);
128         if (findr(y) != x) 
129             link(x, y);
130         else {
131             splay(x);
132             del(rc(x), x);
133             rc(x) = 0; up(x);
134         }
135     }
136 }
137 
138 using namespace LCT;
139 
140 int main()
141 {
142     n = rd; m = rd;
143     for (int i = 1; i <= n; ++i)
144         fa[i] = i;
145     for (int i = 1; i <= m; ++i) {
146         e[i].u = rd; e[i].v = rd;
147         if (e[i].u > e[i].v)
148             swap(e[i].u, e[i].v);
149     }
150     sort(e + 1, e + 1 + m);
151     int Q = 0;
152     for (; ; ) {
153         int op = rd;
154         if (op == -1)
155             break;
156         int u = rd, v = rd;
157         if (u > v)
158             swap(u, v);
159         q[++Q].op = op; q[Q].u = u;
160         q[Q].v = v;
161         edge t;
162         t.u = u; t.v = v;
163         if (op == 0)
164             vis[lower_bound(e + 1, e + 1 + m, t) - e] = 1;
165     }
166     for (int i = 1; i <= m; ++i)
167         if (!vis[i]) 
168             merge(e[i].u, e[i].v);
169     for (int i = Q; i; i--) {
170         if (q[i].op == 1) {
171             int x = q[i].u, y = q[i].v;
172             x = anc(x); y = anc(y);
173             if (x == y) {ans[i] = 0; continue;}
174             split(x, y);
175             ans[i] = sz[y] - 1;
176         }
177         else merge(q[i].u, q[i].v);
178     }
179     for (int i = 1; i <= Q; ++i)
180         if (q[i].op == 1)
181             printf("%d\n", ans[i]);
182 }
View Code

 

BZOJ 1969 航线规划 - LCT 维护边双联通分量

上一篇:HarmonyOS IDL接口类不存在


下一篇:反射全纪录(-)