HDU 6200 mustedge mustedge mustedge [LCT+缩点]

6 篇文章 0 订阅

题意:给你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);
			}
		}
	}
	
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值