思路:有两种操作,一种是删除一条边,另一种是询问点u,v之间的桥的数目,显然删边是不好操作的,一个经典的套路就是离线把操作存起来,从最后的图开始加边,因为题目保证最后的图一定是联通的,所以不用考虑别的,当它最后的图是一棵树的时候,我们设边权为1,那么u,v之间的桥的数目就是两点间的距离,而如果加一条边的话那么u,v会形成环,那么就将它们的边权设为0,对答案没有贡献,那么就可以用并查集将最后的图缩成一棵树,然后树链剖分即可
#include<bits/stdc++.h>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn = 3*1e5+7;
const int maxq = 1e5+7;
#define LL long long
int siz[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],id[maxn];
int tot;
vector<int>e[maxn];
map<int,int>tmp[maxn];
map<int,int>::iterator it;
//vector<pair<int,int> >tmp;
//vector<pair<int,int> >::iterator it;
int n,m,k;
int sum[maxn<<2],lazy[maxn<<2];
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
struct Node
{
int op;
int u,v;
int ans;
}q[maxq];
void push_up(int i)
{
sum[i]=sum[i<<1]+sum[i<<1|1];
}
void build(int i,int l,int r)
{
lazy[i]=0;
if(l==r)
{
sum[i]=1;
return;
}
int mid = (l+r)>>1;
build(lson);
build(rson);
push_up(i);
}
int query(int ql,int qr,int i,int l,int r)
{
if(lazy[i])return 0;
if(ql<=l && qr>=r)
return sum[i];
int mid = (l+r)>>1;
int ans = 0;
if(ql<=mid)
ans+=query(ql,qr,lson);
if(mid<qr)
ans+=query(ql,qr,rson);
return ans;
}
void update(int ql,int qr,int i,int l,int r)
{
if(lazy[i])return;
if(ql<=l&&qr>=r)
{
lazy[i]=1;
sum[i]=0;
return;
}
int mid = (l+r)>>1;
if(ql<=mid)
update(ql,qr,lson);
if(qr>mid)
update(ql,qr,rson);
push_up(i);
}
void dfs1(int u,int f,int d)
{
siz[u]=1;
son[u]=0;
fa[u]=f;
dep[u]=d;
for(int i = 0;i<e[u].size();i++)
{
int v = e[u][i];
if(v==f)continue;
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v])
son[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
id[u]=++tot;
if(son[u])
dfs2(son[u],tp);
for(int i = 0;i<e[u].size();i++)
{
int v = e[u][i];
if(v==fa[u] || v==son[u])
continue;
dfs2(v,v);
}
}
void sccno(int u,int v)
{
int tp1 = top[u],tp2 = top[v];
while(tp1!=tp2)
{
if(dep[tp1]<dep[tp2])
{
swap(tp1,tp2);
swap(u,v);
}
update(id[tp1],id[u],1,1,tot);
u = fa[tp1];
tp1 = top[u];
}
if(u==v)
return;
if(dep[u]>dep[v])
swap(u,v);
update(id[son[u]],id[v],1,1,tot);
}
LL Yougth(int u,int v)
{
int tp1 = top[u],tp2 = top[v];
LL ans = 0;
while(tp1!=tp2)
{
if(dep[tp1]<dep[tp2])
{
swap(tp1,tp2);
swap(u,v);
}
ans+=query(id[tp1],id[u],1,1,tot);
u = fa[tp1];
tp1 = top[u];
}
if(u==v)
return ans;
if(dep[u]>dep[v])
swap(u,v);
ans+=query(id[son[u]],id[v],1,1,tot);
return ans;
}
int p[maxn];
int Find(int x){return p[x]==x?x:p[x]=Find(p[x]);}
void init()
{
for(int i = 0;i<=n;i++)
p[i]=i;
for(int i = 0;i<=n;i++)
tmp[i].clear();
for(int i = 0;i<=n;i++)
e[i].clear();
}
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
printf("Case #%d:\n",cas++);
scanf("%d%d%d",&n,&m,&k);
init();
for(int i = 1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
if(u>v)swap(u,v);
tmp[u][v]++;
//tmp.push_back(make_pair(u,v));
}
for(int i = 1;i<=k;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)
{
it = find(tmp.begin(),tmp.end(),make_pair(q[i].u,q[i].v));
tmp.erase(it);
printf("yes\n");
}*/
if(q[i].op==1)
tmp[q[i].u][q[i].v]--;
}
/*for(int i = 0;i<tmp.size();i++)
{
int u = tmp[i].first;
int v = tmp[i].second;
if(Find(u)!=Find(v))
{
p[Find(u)]=Find(v);
e[u].push_back(v);
e[v].push_back(u);
it = find(tmp.begin(),tmp.end(),make_pair(u,v));
tmp.erase(it);
}
}*/
for(int i = 1;i<=n;i++)
{
for(it = tmp[i].begin();it!=tmp[i].end();it++)
{
if(it->second > 0)
{
int u = i;
int v = it->first;
if(Find(u)!=Find(v))
{
e[u].push_back(v);
e[v].push_back(u);
p[Find(u)]=Find(v);
it->second--;
}
}
}
}
// printf("yes\n");
/*for(int i = 1;i<=n;i++)
{
for(int j = 0;j<e[i].size();j++)
{
printf("%d %d\n",i,e[i][j]);
}
}*/
dfs1(1,-1,0);
dfs2(1,1);
build(1,1,tot);
for(int i = 1;i<=n;i++)
{
for(it = tmp[i].begin();it!=tmp[i].end();it++)
{
if(it->second>0)
{
int u = i,v = it->first;
sccno(u,v);
}
}
}
/*for(int i = 0;i<tmp.size();i++)
{
int u = tmp[i].first;
int v = tmp[i].second;
sccno(u,v);
}*/
for(int i = k;i>=1;i--)
{
if(q[i].op==1)
sccno(q[i].u,q[i].v);
else
q[i].ans = Yougth(q[i].u,q[i].v);
}
for(int i = 1;i<=k;i++)
if(q[i].op==2)
printf("%d\n",q[i].ans);
}
}