题意:给n个点m条边的无向图,图中可能包含自环和重边,现在有两种操作:
1.删掉一条(a,b)边
2.询问a->b上有多少条关键边,关键边意思为:删掉该边,使得a不能到达b。
所有删除操作都保证图是连通的。

把删除操作倒着加边来搞。
先随便建一颗树,边权为1,若加边(a,b),那么a到b的路径上的边权都赋值为0
询问a b则为a->b的边权和。用树链来搞。

//author: CHC
//First Edit Time: 2015-09-21 23:32
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <limits>
using namespace std;
typedef long long LL;
const int MAXN=1e+4 * 3 + 1000;
const int MAXM=1e+5 * 2 + 1000;
const int INF = numeric_limits<int>::max();
const LL LL_INF= numeric_limits<LL>::max();
struct Edge {
int to,next;
Edge(){}
Edge(int _to,int _next):to(_to),next(_next){}
bool operator<(const Edge &x) const {
if(to!=x.to)return to<x.to;
return next<x.next;
}
}e[MAXM];
int head[MAXN],tot;
int path[MAXN];
int Find(int x){
int tx=x;
while(tx!=path[tx])tx=path[tx];
while(x!=path[x]){
int t=path[x];
path[x]=tx;
x=t;
}
return tx;
//return x==path[x]?x:path[x]=Find(path[x]);
}
bool Union(int x,int y){
x=Find(x),y=Find(y);
if(x==y)return false;
path[x]=y;
return true;
}
multiset <Edge> S,V;
multiset <Edge> ::iterator it,it1;
void init(){
memset(head,-1,sizeof(head));
tot=0;
S.clear();V.clear();
for(int i=1;i<MAXN;i++)path[i]=i;
}
void AddEdge(int u,int v){
e[tot]=Edge(v,head[u]);
head[u]=tot++;
e[tot]=Edge(u,head[v]);
head[v]=tot++;
}
int dep[MAXN],son[MAXN],siz[MAXN],fa[MAXN],prew[MAXN];
int tim,id[MAXN],rid[MAXN],top[MAXN];
void dfs1(int u,int father,int w){
fa[u]=father;siz[u]=1;son[u]=-1;
prew[u]=w;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v!=father){
dep[v]=dep[u]+1;
dfs1(v,u,1);
siz[u]+=siz[v];
if(son[u]==-1||siz[v]>siz[son[u]])son[u]=v;
}
}
}
void dfs2(int u,int tp){
top[u]=tp; id[u]=++tim; rid[tim]=u;
if(son[u]==-1)return ;
dfs2(son[u],tp);
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v!=son[u]&&v!=fa[u])dfs2(v,v);
}
}
#define lson L,mid,rt<<1
#define rson mid+1,R,rt<<1|1
struct Tree {
int ans,flag;
}tr[MAXN<<2];
void pushup(int rt){
tr[rt].ans=tr[rt<<1].ans+tr[rt<<1|1].ans;
}
void pushdown(int rt){
if(tr[rt].flag){
tr[rt<<1].ans=tr[rt<<1|1].ans=0;
tr[rt<<1].flag=tr[rt<<1|1].flag=1;
tr[rt].flag=0;
}
}
void build(int L,int R,int rt){
tr[rt].flag=0;
if(L==R){
tr[rt].ans=prew[rid[L]];
tr[rt].flag=0;
return ;
}
int mid=(L+R)>>1;
build(lson);build(rson);
pushup(rt);
}
void update(int L,int R,int rt,int l,int r){
if(tr[rt].ans==0)return ;
if(l<=L&&R<=r){
tr[rt].ans=0;
tr[rt].flag=1;
return ;
}
pushdown(rt);
int mid=(L+R)>>1;
if(l<=mid)update(lson,l,r);
if(r>mid)update(rson,l,r);
pushup(rt);
}
int query(int L,int R,int rt,int l,int r){
if(tr[rt].ans==0)return 0;
if(l<=L&&R<=r)return tr[rt].ans;
pushdown(rt);
int mid=(L+R)>>1,ans=0;
if(l<=mid)ans+=query(lson,l,r);
if(r>mid)ans+=query(rson,l,r);
pushup(rt);
return ans;
}
void updatex(int a,int b,int n){
while(top[a]!=top[b]){
if(dep[top[a]]<dep[top[b]])swap(a,b);
update(1,n,1,id[top[a]],id[a]);
a=fa[top[a]];
}
if(a==b)return ;
if(dep[a]>dep[b])swap(a,b);
update(1,n,1,id[son[a]],id[b]);
}
int queryx(int a,int b,int n){
int ans=0;
while(top[a]!=top[b]){
if(dep[top[a]]<dep[top[b]])swap(a,b);
ans+=query(1,n,1,id[top[a]],id[a]);
a=fa[top[a]];
}
if(a==b)return ans;
if(dep[a]>dep[b])swap(a,b);
ans+=query(1,n,1,id[son[a]],id[b]);
return ans;
}
struct Q {
int type,a,b;
void init(){
scanf("%d%d%d",&type,&a,&b);
}
}cs[MAXN*10];
int ans[MAXN*10];
int main()
{
int T,n,m,q,cas=0;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&q);
init();
for(int i=0,x,y;i<m;i++){
scanf("%d%d",&x,&y);
if(x>y)swap(x,y);
S.insert(Edge(x,y));
}
//puts("here");
for(int i=0;i<q;i++){
cs[i].init();
if(cs[i].type==1){
if(cs[i].a>cs[i].b)swap(cs[i].a,cs[i].b);
it=S.lower_bound(Edge(cs[i].a,cs[i].b));
S.erase(it);
}
}
//puts("here");
for(it=S.begin();it!=S.end();it++){
if(Union(it->to,it->next)){
V.insert(*it);
AddEdge(it->to,it->next);
}
}
//puts("here3");

for(it=V.begin();it!=V.end();it++){
it1=S.lower_bound(*it);
S.erase(it1);
}

//puts("here");
dep[1]=0;
tim=0;
dfs1(1,1,0);
dfs2(1,1);
build(1,n,1);
for(it=S.begin();it!=S.end();it++){
updatex(it->next,it->to,n);
}
for(int i=q-1;i>=0;i--){
if(cs[i].type==1){
updatex(cs[i].a,cs[i].b,n);
}
else {
ans[i]=queryx(cs[i].a,cs[i].b,n);
}
}
printf("Case #%d:\n",++cas);
for(int i=0;i<q;i++)
if(cs[i].type==2)printf("%d\n",ans[i]);
}
return 0;
}