题意:
n个点的无向图,Q次操作,每次操作可以连接增加一条边,询问两个点之间有多少条边是必经之路。如果不连通,输出-1。
分析:
首先并查集维护连通性,每次加入一条边后,如果这条边将会连接两个联通块,那么lct连接两个点,边权化为点权,新增一个点,点权为1。否则,构成了环,环上的边都变为0,lct维护覆盖标记。询问就是对一条链进行询问。
离线+树剖的做法:从前往后建出树,如果出现环则不加入,然后树剖,每次出现一条非树边就是将环上的边赋值为0,询问就是两点之间的边权和。
代码:
lct
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cctype>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
struct LCT{
#define lc ch[rt][0]
#define rc ch[rt][1]
int siz[N], val[N], ch[N][], fa[N], sk[N], rev[N], tag[N], Index;
inline bool isroot(int x) { return ch[fa[x]][] != x && ch[fa[x]][] != x; }
inline bool son(int x) { return x == ch[fa[x]][]; }
inline void pushup(int rt) { siz[rt] = siz[lc] + siz[rc] + val[rt]; }
inline void pushdown(int rt) {
if (rev[rt]) {
swap(lc, rc);
rev[lc] ^= , rev[rc] ^= ; rev[rt] ^= ;
}
if (tag[rt]) {
tag[lc] = tag[rc] = ;
siz[lc] = siz[rc] = val[lc] = val[rc] = tag[rt] = ;
}
}
void rotate(int x) {
int y = fa[x], z = fa[y], c = son(y), b = son(x), a = ch[x][!b];
if (!isroot(y)) ch[z][c] = x; fa[x] = z;
ch[x][!b] = y, fa[y] = x;
ch[y][b] = a; if (a) fa[a] = y;
pushup(y); pushup(x);
}
void splay(int x) {
int top = ; sk[top] = x;
for (int i = x; !isroot(i); i = fa[i]) sk[++top] = fa[i];
while (top) pushdown(sk[top --]); // 注意下pushdown到x的下一层
while (!isroot(x)) {
int y = fa[x], z = fa[y];
if (isroot(y)) rotate(x);
else {
if (son(x) == son(y)) rotate(y), rotate(x);
else rotate(x), rotate(x);
}
}
}
void access(int x) {
for (int last = ; x; last = x, x = fa[x])
splay(x), ch[x][] = last, pushup(x);
}
void makeroot(int x) {
access(x); splay(x); rev[x] ^= ;
}
void link(int x,int y) {
makeroot(x); fa[x] = y;
}
void add(int x,int y) {
val[++Index] = ; link(x, Index); link(Index, y);
}
void split(int x,int y) {
makeroot(x); access(y); splay(y);
}
#undef lc
#undef rc
}lct;
int fa[N];
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
int main() {
int n = read(), m = read(); lct.Index = n;
for (int i = ; i <= n; ++i) fa[i] = i;
while (m --) {
int opt = read(), x = read(), y = read(), tx = find(x), ty = find(y);
if (opt == ) {
if (tx != ty) fa[tx] = ty, lct.add(x, y);
else lct.split(x, y), lct.tag[y] = , lct.val[y] = lct.siz[y] = ;
} else {
if (tx != ty) puts("-1");
else lct.split(x, y), printf("%d\n", lct.siz[y]);
}
}
return ;
}