e_Dcc 缩点求条
查看原帖
e_Dcc 缩点求条
423520
wizard(偷开O2楼主2024/11/21 20:31

http://poj.org/problem?id=3694

题意就是给一个无向连通图动态加边,对于每次询问输出图中的桥的数量。

考虑先对原图进行缩点求出edcc,然后考虑加边后树上会产生环,然后对于两个点求lca,两个点到lca的路径上的桥就全都不是桥了。

但是写炸了,求条。

//ways:傻逼缩点
//orz aqx wvr zak 
//noip 2024 rp++ 
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define int long long
//#define ls ch[now][0]
//#define rs ch[now][1]
//#define mid ((x+y)>>1)
//#define checkbug cout << "okok" << endl;
//#define len (r-l+1)
const int maxn=1e5+10;
const int inf=1e9;
const int maxa=2e3+10;
inline int read(){
	int 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-48;ch=getchar();}
	return x*f;
}
int to[maxn],tot,nxt[maxn],head[maxn];
int head2[maxn],nxt2[maxn],to2[maxn],tot2;
bool bridge[maxn];
int n,m,ans;
void adde(int x,int y){
	to[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
void addc(int x,int y){
	to2[++tot2]=y;
	nxt2[tot2]=head2[x];
	head2[x]=tot2;
}
int dfn[maxn],low[maxn],num;
void tarjan(int x,int root){
	dfn[x]=low[x]=++num;
	for(int i=head[x];i;i=nxt[i]){
		int tox=to[i];
		if(!dfn[tox]){
			tarjan(tox,i);
			low[x]=min(low[x],low[tox]);
			if(low[tox]>dfn[x]){
				bridge[i]=bridge[i^1]=1;
				ans++;
			}
		}else if(i!=(root^1)){
			low[x]=min(low[x],dfn[tox]);
		}
	}
}
int dcc;
int c[maxn];
void dfs(int x){
	c[x]=dcc;
	for(int i=head[x];i;i=nxt[i]){
		int tox=to[i];
		if(c[tox]||bridge[i]){
			continue;
		}
		dfs(tox);
	}
}
int dep[maxn];
int fa[maxn][25];
void dfs2(int x,int fax){
	fa[x][0]=fax;
	dep[x]=dep[fax]+1;
	for(int i=0;fa[x][i];i++){
		fa[x][i+1]=fa[fa[x][i]][i];
	}
	for(int i=head2[x];i;i=nxt2[i]){
		int tox=to2[i];
		if(tox!=fax){
			dfs2(tox,x);
		}
	}
}
int lca(int x,int y){
	if(dep[x]>dep[y]){
		swap(x,y);
	}
	for(int i=20;i>=0;i--){
		if(dep[x]<=dep[y]-(1<<i)){
			y=fa[y][i];
		}
	}
	if(x==y){
		return x;
	}
	for(int i=20;i>=1;i--){
		if(fa[x][i]!=fa[y][i]){
			x=fa[x][i];
			y=fa[y][i];
		}
	}
	return fa[x][0];
}
int f[maxn];
int find(int x){
	while(x!=f[x]){
		x=f[x]=f[f[x]];
	}
	return x;
}
void init(){
	memset(bridge,0,sizeof(bridge));
	memset(head,0,sizeof(head));
	memset(head2,0,sizeof(head2));
	for(int i=0;i<=n;i++){
		f[i]=i;
	}
	ans=dcc=num=0;
	tot=tot2=-1;
}
int id=1;
signed main(){
	while((n=read())|(m=read())){
		init();
		for(int i=1;i<=m;i++){
			int x,y;
			cin >>x >> y;
			adde(x,y);
			adde(y,x);
		}
		for(int i=1;i<=n;i++){
			if(!dfn[i]){
				tarjan(i,0);
			}
		}
		for(int i=1;i<=n;i++){
			if(!c[i]){
				++dcc;dfs(i);
			}
		}
		for(int i=0;i<=tot;i++){
			int x=to[i],y=to[i^1];
			if(c[x]==c[y]){
				continue;
			}
			addc(c[x],c[y]);
			addc(c[y],c[x]);
		}
		dfs2(1,0);
		int q;
		cin >> q;
		cout << "Case " << id++ << ":" << endl;
		while(q--){
			int nowx,nowy;
			cin >> nowx >> nowy;
			int x=c[nowx],y=c[nowy];
			int Lca=lca(x,y);
			x=find(x),y=find(y);
			while(dep[x]>dep[Lca]){
				f[x]=find(fa[x][0]);
				x=find(x);
				ans--;
			}
			while(dep[y]>dep[x]){
				f[y]=find(fa[x][0]);
				y=find(y);
				ans--;
			}
			cout << ans << endl;
		}
		cout << endl;
	}
	return 0;
}
2024/11/21 20:31
加载中...