题意:给出n个点、m条边(可能有环、重边)、q个询问~~
询问1:=删除某一条边<a,b>
询问2:=问<a,b>路径中有多少条桥~~~
桥、如果将环收缩的话,图会变成一个树。那么有多少条桥也就是问路径<a,b>的大小。
即deep[a]+deep[b]-a*deep[lca(a,b)].
首先图是删边的,很麻烦~~所有离线逆过来处理。
对于要“添加的边“先标记。
利用剩下的没有动过的边跑一趟dfs序成一个完整的树
并记录下deep[](深度),当前节点对应的编号idx、当前节点子树的区间lr[u]....
然后利用刚才没有用过的非添加的边进行缩点,当每减少一条桥,某一刻孩子树将会往上提高一个高度。
这个信息可以用树状数组进行维护~~~~
同时也用一个并查集维护缩点信息~~~
#include <algorithm>
#include <iostream>
#include<string.h>
#include <fstream>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define exp 1e-8
#define fi first
#define se second
#define ll long long
#define INF 0x3f3f3f3f
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define all(a) a.begin(),a.end()
#define mm(a,b) memset(a,b,sizeof(a));
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define rep(a,b,c) for(int a=b;a<=c;a++)//b---c
#define repp(a,b,c)for(int a=b;a>=c;a--)///
#define stl(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
using namespace std;
void bug(string m="here"){cout<<m<<endl;}
template<typename __ll> inline void READ(__ll &m){__ll x=0,f=1;char ch=getchar();while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}m=x*f;}
template<typename __ll>inline void read(__ll &m){READ(m);}
template<typename __ll>inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c){READ(m);READ(a);READ(b);READ(c);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c,__ll &d){READ(m);READ(a);READ(b);READ(c);read(d);}
template < class T > T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template < class T > T lcm(T a, T b) { return a / gcd(a, b) * b; }
template < class T > inline void rmin(T &a, const T &b) { if(a > b) a = b; }
template < class T > inline void rmax(T &a, const T &b) { if(a < b) a = b; }
template < class T > T pow(T a, T b) { T r = 1; while(b > 0) { if(b & 1) r = r * a; a = a * a; b /= 2; } return r; }
template < class T > T pow(T a, T b, T mod) { T r = 1; while(b > 0) { if(b & 1) r = r * a % mod; a = a * a % mod; b /= 2; } return r; }
const int maxn=30010;
int n,m,q;
int idx[maxn];
int kk,lr[maxn][3];
int deep[maxn];
int fa[maxn][20];
int belong[maxn];
struct edge
{
int v,del;
edge(){}
edge(int vv){v=vv,del=0;}
bool operator < (const edge &rhs) const{
if(v!=rhs.v)return v<rhs.v;
return del>rhs.del;
}
};
vector<edge>vec[maxn];
struct QUERY
{
int op,a,b,ans;
void READ()
{
read(op,a,b);
ans=-1;
if(op==1)
{
lower_bound(all(vec[a]),edge(b))->del=1;
lower_bound(all(vec[b]),edge(a))->del=1;
}
}
}query[100010];
void init()
{
kk=1;
for1(i,n)vec[i].clear();
for1(i,n)belong[i]=i;
memset(deep,0,sizeof deep);
}
void dfs_id(int u,int ff,int dee)
{
deep[u]=dee;
fa[u][0]=ff;
lr[u][1]=kk;
for(int i=0;i<vec[u].size();i++)
{
if(vec[u][i].del==1)continue;
int v=vec[u][i].v;
if(v==ff)
{
vec[u].erase(vec[u].begin()+i);///删除与父亲的联系啦~~~~
i--;
continue;
}
if(deep[v]!=0)continue;
vec[u].erase(vec[u].begin()+i);///删除与孩子的联系啦~~~~
i--;
dfs_id(v,u,dee+1);
}
idx[u]=lr[u][2]=kk++;
}
struct LCA
{
void init()
{
///p[i][j]表示i结点的第2^j祖先
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++)
if(fa[i][j-1]!=-1)
fa[i][j]=fa[fa[i][j-1]][j-1];///i的第2^j祖先就是i的第2^(j-1)祖先的第2^(j-1)祖先
}
int ask(int a,int b)///最近公共祖先
{
int i,j;
if(deep[a]<deep[b])swap(a,b);
for(i=0;(1<<i)<=deep[a];i++);
i--;
///使a,b两点的深度相同
for(j=i;j>=0;j--)
if(deep[a]-(1<<j)>=deep[b])
a=fa[a][j];
if(a==b)return a;
///倍增法,每次向上进深度2^j,找到最近公共祖先的子结点
for(j=i;j>=0;j--)
{
if(fa[a][j]!=-1&&fa[a][j]!=fa[b][j])
{
a=fa[a][j];
b=fa[b][j];
}
}
return fa[a][0];
}
}lca;
struct bit_tree
{
int Tree[maxn];
inline int lowbit(int x){return x&-x;}
void init()
{
memset(Tree,0,sizeof Tree);
}
void modify(int x,int y,int val)
{
doit(x,val);
doit(y+1,-val);
}
void doit(int x,int val)
{
for(int i=x;i<=n;i+=lowbit(i)) //n为区间总长度,1---n
Tree[i]+=val;
}
int sum(int x)
{
int res=0;
for(int i=x;i>0;i-=lowbit(i))
res+=Tree[i];
return res;
}
}tree;
int find(int k)
{
if(belong[k]!=k)
belong[k]=find(belong[k]);
return belong[k];
}
void merge_fa(int a,int b)
{
a=find(a);
b=find(b);
while(a!=b)
{
int par=find(fa[a][0]);///
belong[a]=par;
tree.modify(lr[a][1],lr[a][2],-1);
a=par;
}
}
void merge(int a,int b)
{
int l=lca.ask(a,b);
merge_fa(a,l);
merge_fa(b,l);
}
void merge_ret()
{
for(int u=1;u<=n;u++)
for(int i=0;i<vec[u].size();i++)
{
if(vec[u][i].del==1)continue;
merge(u,vec[u][i].v);
}
}
int get_ans(int a,int b)
{
int l=lca.ask(a,b);
int nowa=deep[a]+tree.sum(idx[a]);
int nowb=deep[b]+tree.sum(idx[b]);
int nowl=deep[l]+tree.sum(idx[l]);
return nowa+nowb-2*nowl;
}
void solve()
{
tree.init();
dfs_id(1,1,1);
lca.init();
merge_ret();
for(int i=q;i>=1;i--)
{
if(query[i].op==1)
merge(query[i].a,query[i].b);
else
query[i].ans=get_ans(query[i].a,query[i].b);
}
for1(i,q)if(query[i].ans!=-1)printf("%d\n",query[i].ans);
}
int main()
{
int cas;
read(cas);
for1(tt,cas)
{
read(n,m,q);
init();
for1(i,m)
{
int a,b;read(a,b);
vec[a].pb(edge(b));
vec[b].pb(edge(a));
}
for1(i,n)sort(all(vec[i]));
for1(i,q)query[i].READ();
printf("Case #%d:\n", tt);
solve();
}
}