这个题目,只要想到离线,然后先建一颗树,树链剖分一下,logn的时间维护一段路径,就可以了。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 30000 + 10;
const int maxm = 100000 + 10;
int n,m,Q;
struct Edge
{
int from,to;
Edge(){}
Edge(int a,int b):from(a),to(b){}
bool operator < (const Edge &A) const {
return from == A.from ? to < A.to : from < A.from;
}
}edge;
struct Qu
{
int op,u,v;
}q[maxm];
multiset<Edge>s;
vector<int>G[maxn];
int Fa[maxn],Rank[maxn];
int find(int x)
{
if(x!=Fa[x]) Fa[x] = find(Fa[x]);
return Fa[x];
}
void unio(int a,int b){
int fx = find(a),fy = find(b);
if( Rank[fx] > Rank[fy] ){
Fa[ fy ] = fx;
Rank[fx] ++;
}
else{
Fa[ fx ] = fy;
Rank[fy] ++ ;
}
}
///线段树部分
struct Segment
{
#define rt get_id(l,r)
#define ls get_id(l,mid)
#define rs get_id(mid+1,r)
int get_id(int l,int r){
return l + r | l != r;
}
int sum[maxn<<1],root[maxn<<1];
void up(int l,int r){
int mid = l + r >> 1;
sum[rt] = sum[ls] + sum[rs];
}
void down(int l,int r){
int mid = l + r >> 1;
if(root[rt]){
root[ls] = root[rs] = root[rt];
sum[ls] = sum[rs] = 0;
root[rt] = 0;
}
}
void build(int l,int r){
root[rt] = 0;
if( l == r){
sum[rt] = 1;
return ;
}
int mid = l + r >> 1;
build(l,mid);
build(mid+1,r);
up(l,r);
}
void update(int l,int r,int L,int R)
{
if(L<=l && R>=r){
sum[rt] = 0;
root[rt] = 1;
return ;
}
int mid = l + r >> 1;
down(l,r);
if(L<=mid) update(l,mid,L,R);
if(R>mid) update(mid+1,r,L,R);
up(l,r);
}
int query(int l,int r,int L,int R)
{
if(L<=l && R>=r){
return sum[rt];
}
down(l,r);
int mid = l + r >> 1,res = 0;
if(L<=mid) res += query(l,mid,L,R);
if(R>mid) res += query(mid+1,r,L,R);
return res;
}
}seg;
///
///树剖部分
int tree[maxn];
int z,root;
int dep[maxn], w[maxn], fa[maxn], top[maxn], son[maxn], siz[maxn];
void dfs(int v)
{
siz[v] = 1;
son[v] = 0;
for (int i = 0; i < G[v].size(); i ++ )
if (G[v][i] != fa[v])
{
fa[ G[v][i] ] = v;
dep[ G[v][i] ] = dep[v]+1;
dfs( G[v][i] );
if (siz[ G[v][i] ] > siz[son[v]]) son[v] = G[v][i];
siz[v] += siz[ G[v][i] ];
}
}
void build_tree(int v, int tp)
{
w[v] = ++ z;
top[v] = tp;
if (son[v] != 0) build_tree(son[v], top[v]);
for (int i = 0; i < G[v].size(); i ++)
if (G[v][i] != son[v] && G[v][i] != fa[v])
build_tree(G[v][i], G[v][i]);
}
void init()
{
root = 1;
fa[root] = z = dep[root] = 0;
memset(siz, 0, sizeof(siz));
memset(tree, 0, sizeof(tree));
dfs(root);
build_tree(root,root);
}
inline void find(int va, int vb)
{
int f1 = top[va], f2 = top[vb];
while (f1 != f2){
if (dep[f1] < dep[f2]){
swap(f1, f2);
swap(va, vb);
}
seg.update(1,z,w[f1],w[va]);
va = fa[f1];
f1 = top[va];
}
if (va == vb) return ;
if (dep[va] > dep[vb]) swap(va, vb);
seg.update(1,z,w[ son[va] ],w[vb]);
return ;
}
inline int query(int va, int vb)
{
int f1 = top[va], f2 = top[vb], tmp = 0;
while (f1 != f2){
if (dep[f1] < dep[f2]){
swap(f1, f2);
swap(va, vb);
}
tmp += seg.query(1,z,w[f1],w[va]);
va = fa[f1];
f1 = top[va];
}
if (va == vb) return tmp;
if (dep[va] > dep[vb]) swap(va, vb);
tmp += seg.query(1,z,w[ son[va] ],w[vb]);
return tmp;
}
///
int ans[maxm];
bool vis[maxm];
int main()
{
int T,cas=0;scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&Q);
s.clear();
for(int i=1;i<=m;i++) {
scanf("%d%d",&edge.from,&edge.to);
if(edge.from > edge.to) swap(edge.from,edge.to);
s.insert(edge);
}
for(int i=1;i<=n;i++) G[i].clear(),Fa[i] = i,Rank[i] = 1;
for(int i=1;i<=Q;i++) {
scanf("%d%d%d",&q[i].op,&q[i].u,&q[i].v);
if(q[i].u > q[i].v) swap(q[i].u,q[i].v);
if(q[i].op == 1){
s.erase(s.find(Edge(q[i].u,q[i].v)));
}
}
int id = 0;
memset(vis,0,sizeof(vis));
for(multiset<Edge>::iterator it = s.begin();it!=s.end();it++)
{
id ++ ;
Edge k = (*it);
if(find(k.from) == find(k.to)) continue;
G[k.from].push_back(k.to);
G[k.to].push_back(k.from);
unio(k.from,k.to);
vis[ id ] = 1;
}
init();
seg.build(1,z);
id = 0;
for(multiset<Edge>::iterator it = s.begin();it!=s.end();it++)
{
id++;
Edge k = (*it);
if(vis[id]) continue;
int a = k.from,b = k.to;
find(a,b);
}
for(int i=Q;i>=1;i--)
if(q[i].op == 2){
ans[i] = query(q[i].u,q[i].v);
}
else{
find(q[i].u,q[i].v);
}
printf("Case #%d:\n",++cas);
for(int i=1;i<=Q;i++) {
if(q[i].op == 2) printf("%d\n",ans[i]);
}
}
}