题目大意
给出一张连通图,现在有两种操作:
⋅1 u v
:向图中加入一条连接
u
和
⋅2 u v
:询问
u
和
思路
首先随便找到一个生成树,每条边的初始权值为1,对于所有非树边
(u,v)
,将生成树上
u
到
然后考虑加边操作,因为每一条边只会被删除一次,所以我们可以记录每一个节点在它到根的路径上离它最近的一个没有被删除的边,通过并查集维护。
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m, q, t[MAXN], f[MAXN], fa[MAXN], adj[MAXN], c, out[MAXN], dfn[MAXN];
int edge[MAXN][2], dcnt, sz[MAXN], hsn[MAXN], htp[MAXN], dep[MAXN];
struct { int v, nxt; } e[MAXN << 1];
inline void Addedge(int u, int v) {
e[++ c].v = v; e[c].nxt = adj[u]; adj[u] = c;
}
inline void GET(int&n) {
static char c; n = 0;
do c = getchar(); while('0' > c || c > '9');
while('0' <= c && c <= '9') { n = n * 10 + c - '0'; c = getchar(); }
}
inline void Add(int x, int v) {
for(; x <= n; x += x&-x) t[x] += v;
}
inline int Qsum(int x) {
int ans = 0;
for(; x > 0; x -= x&-x) ans += t[x];
return ans;
}
int Find(int x) { return (x == f[x]) ? x : (f[x] = Find(f[x])); }
void dfs(int u) {
dep[u] = dep[fa[u]] + 1; dfn[u] = ++ dcnt; sz[u] = 1; hsn[u] = 0;
for(int i = adj[u]; i; i = e[i].nxt) if(e[i].v != fa[u]) {
fa[e[i].v] = u;
dfs(e[i].v); sz[u] += sz[e[i].v];
if(sz[e[i].v] > sz[hsn[u]]) hsn[u] = e[i].v;
}
out[u] = dcnt;
}
void dfs2(int u, int tp) {
htp[u] = tp;
if(hsn[u]) dfs2(hsn[u], tp);
for(int i = adj[u]; i ; i = e[i].nxt)
if(e[i].v != fa[u] && e[i].v != hsn[u])
dfs2(e[i].v, e[i].v);
}
int LCA(int u, int v) {
while(htp[u] != htp[v]) {
if(dep[htp[u]] < dep[htp[v]]) swap(u, v);
u = fa[htp[u]];
}
return dep[u] < dep[v] ? u : v;
}
void Adde(int u, int v) { //to add not_in_tree edge
int lca = LCA(u, v), a = u, b = v, x;
for(; dep[(x = Find(a))] > dep[lca]; a = fa[x]) {
Add(dfn[x], -1); Add(out[x]+1, 1); f[x] = Find(fa[x]);
}
for(; dep[(x = Find(b))] > dep[lca]; b = fa[x]) {
Add(dfn[x], -1); Add(out[x]+1, 1); f[x] = Find(fa[x]);
}
}
int Query(int u) {
return dep[u] + Qsum(dfn[u]);
}
int main() {
int T, u, v, cnt, op; cin >> T;
for(int Cas = 1; Cas <= T; ++ Cas) {
cin >> n >> m; cnt = dcnt = c = 0;
for(int i = 1; i <= n; ++ i) f[i] = i, adj[i] = 0, t[i] = 0;
for(int i = 1; i <= m; ++ i) {
GET(u); GET(v);
if(Find(u) != Find(v)) {
Addedge(u, v);
Addedge(v, u);
f[Find(u)] = Find(v);
} else {
edge[++ cnt][0] = u;
edge[cnt][1] = v;
}
}
fa[1] = 0;
dfs(1); dfs2(1, 1);
for(int i = 1; i <= n; ++ i) f[i] = i;
for(int i = 1; i <= cnt; ++ i)
Adde(edge[i][0], edge[i][1]);
scanf("%d", &q);
printf("Case #%d:\n", Cas);
for(int i = 1; i <= q; ++ i) {
GET(op); GET(u); GET(v);
if(op == 1) Adde(u, v);
else printf("%d\n", Query(u) + Query(v) - 2 * Query(LCA(u, v)));
}
}
return 0;
}