题意:给你n个点m条边,有q个操作:
①u和v之间加入一条边;
②询问u和v之间的桥的个数;
题解:刚刚开始的时候还以为需要边化点,后来发现其实只要记录bcc分量的个数减一就是桥的个数(因为是棵树= =),这样我们就可以通过LCT维护bcc,然后通过缩点减少复杂度和计算答案。(这里T了好久)
首先对于新加入的边,我们make_root(u);access(v);splay(v);得到这个环上的所有点,然后搜索这个splay上的所有点,连接到新的节点。
对于询问我们make_root(u);access(v);splay(v); 然后输入sum[v]-1就可得到u到v的桥的数量。
(注意:LCT模板中的pre[x]都需要找到最终的bcc所属)
AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 200005
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int _read(){
char ch=nc();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
int rev[N],ch[N][2],pre[N],fa[N],st[N],sum[N],have[N],bcc[N],t,n;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}//并查集
int find2(int x){return bcc[x]==x?x:bcc[x]=find2(bcc[x]);}//并查集
bool is_root(int x){return ch[find2(pre[x])][0]!=x&&ch[bcc[pre[x]]][1]!=x;}
void reverse(int x)
{
rev[x]^=1;swap(ch[x][0],ch[x][1]);
rev[ch[x][0]]^=1;rev[ch[x][1]]^=1;
}
void update(int x)
{
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+have[x];
}
void rotate(int x)
{
int y=find2(pre[x]),z=find2(pre[y]);
bool f=ch[y][1]==x;
if(!is_root(y))ch[z][ch[z][1]==y]=x;
ch[y][f]=ch[x][!f];ch[x][!f]=y;
pre[x]=z;pre[y]=x;pre[ch[y][f]]=y;
update(y);update(x);
}
void splay(int x)
{
st[t=1]=x;
for(int y=x;!is_root(y);st[++t]=y=find2(pre[y]));
for(;t;t--)if(rev[st[t]])reverse(st[t]);
for(;!is_root(x);rotate(x))if(!is_root(find2(pre[x])))
ch[bcc[pre[x]]][0]==x^ch[find2(pre[bcc[pre[x]]])][0]==bcc[pre[x]]?rotate(x):rotate(bcc[pre[x]]);
update(x);
}
void access(int x){for(int t=0;x;ch[x][1]=t,t=x,x=find2(pre[x])){if(t)update(t);splay(x);}}
void make_root(int x){access(x);splay(x);rev[x]^=1;}
void link(int x,int y){make_root(x);make_root(y);pre[x]=y;}//将x的父亲设为y
void cut(int x,int y){make_root(x);access(y);splay(y);pre[x]=ch[y][0]=0;}
void rebuild(int root,int n)
{
if(root==0)return ;
bcc[root]=n;
rebuild(ch[root][0],n);
rebuild(ch[root][1],n);
}
int main()
{
//freopen("data.txt","r",stdin);
int T,cas=1;
T=_read();
while(T--)
{
memset(rev,0,sizeof(rev));
memset(ch,0,sizeof(ch));
memset(pre,0,sizeof(pre));
memset(st,0,sizeof(st));
for(int i=1;i<N;i++)fa[i]=bcc[i]=i,sum[i]=have[i]=1;
int n,m;
n=_read();m=_read();
for(int i=0;i<m;i++)
{
int u,v;
u=_read();v=_read();
int t1=find(u),t2=find(v);
find2(u);find2(v);
if(t1!=t2)link(bcc[u],bcc[v]),fa[t2]=t1;
else
{
if(bcc[u]==bcc[v])continue;
make_root(bcc[u]);
access(bcc[v]);
splay(bcc[v]);
n++;have[n]=sum[n]=1;
rebuild(bcc[v],n);
}
}
int q;
q=_read();
printf("Case #%d:\n",cas++);
while(q--)
{
int op,u,v;
op=_read();u=_read();v=_read();
if(op==1)
{
int t1=find(u),t2=find(v);
find2(u);find2(v);
if(t1!=t2)link(bcc[u],bcc[v]),fa[t2]=t1;
else
{
if(bcc[u]==bcc[v])continue;
make_root(bcc[u]);
access(bcc[v]);
splay(bcc[v]);
n++;have[n]=sum[n]=1;
rebuild(bcc[v],n);
}
}
else
{
int t1=find(u),t2=find(v);
find2(u);find2(v);
if(t1!=t2)
{
printf("0\n");
continue;
}
make_root(bcc[u]);
access(bcc[v]);
splay(bcc[v]);
printf("%d\n",sum[bcc[v]]-1);
}
}
}
}