POJ3694 Network

Network

给一个无向图,该图只有一个连通分量。然后查询q次,q < 1000,
求每次查询就增加一条边,求剩余桥的个数。

题解

参照zhengnanlee的题解。

求双连通分量,利用并查集缩点,形成一棵树,树边肯定都是桥,然后每对点x,y,找原图中x,y点对应的新图中的点,如果不是一个点,则向上找它们的LCA,因为它们之间连了一条边,所以这些点到它们的LCA之间的边都不是割边了,找LCA时,先将两点上升到同一层次,然后一起再向上找父亲节点,其间遇到桥就把桥的标记删除,并且答案减1。

时间复杂度\(O(m+q\log n)\)

#include<iostream>
#include<queue>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
    for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;

co int N=2e5+1;
int head[N],ver[N*2],next[N*2];
int dfn[N],low[N],c[N];
int n,m,t,tot,num,dcc,tc,T;
bool bridge[N*2],v[N];
int hc[N],vc[N*2],nc[N*2];
int d[N],f[N][19],fa[N];
std::queue<int> q;

il void add(int x,int y){
	ver[++tot]=y,next[tot]=head[x],head[x]=tot;
}
il void add_c(int x,int y){
	vc[++tc]=y,nc[tc]=hc[x],hc[x]=tc;
}
void tarjan(int x,int in_edge){
	dfn[x]=low[x]=++num;
	for(int i=head[x];i;i=next[i]){
		int y=ver[i];
		if(!dfn[y]){
			tarjan(y,i);
			low[x]=std::min(low[x],low[y]);
			if(low[y]>dfn[x])
				bridge[i]=bridge[i^1]=1;
		}
		else if(i!=(in_edge^1))
			low[x]=std::min(low[x],dfn[y]);
	}
}
void dfs(int x){
	c[x]=dcc;
	for(int i=head[x];i;i=next[i]){
		int y=ver[i];
		if(c[y]||bridge[i]) continue;
		dfs(y);
	}
}
void bfs(){
	d[1]=1,q.push(1);
	while(q.size()){
		int x=q.front();q.pop();
		for(int i=hc[x];i;i=nc[i]){
			int y=vc[i];
			if(d[y]) continue;
			d[y]=d[x]+1;
			f[y][0]=x;
			for(int j=1;j<18;++j)
				f[y][j]=f[f[y][j-1]][j-1];
			q.push(y);
		}
	}
}
int lca(int x,int y){
	if(d[x]<d[y]) std::swap(x,y);
	for(int i=17;i>=0;--i)
		if(d[f[x][i]]>=d[y]) x=f[x][i];
	if(x==y) return x;
	for(int i=17;i>=0;--i)
		if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0];
}
int get(int x){
	return fa[x]==x?x:fa[x]=get(fa[x]);
}
int main(){
	while(read(n)|read(m)){
		tot=1,num=dcc=0;
		for(int i=1;i<=n;++i)
			head[i]=dfn[i]=hc[i]=d[i]=c[i]=0;
		for(int i=1;i<=2*m+1;++i)
			bridge[i]=0;
		for(int i=1,x,y;i<=m;++i)
			read(x),read(y),add(x,y),add(y,x);
		tarjan(1,0);
		for(int i=1;i<=n;++i)
			if(!c[i]) ++dcc,dfs(i);
		tc=1;
		for(int i=2;i<=tot;++i){
			int x=ver[i^1],y=ver[i];
			if(c[x]==c[y]) continue;
			add_c(c[x],c[y]);
		}
		bfs();
		for(int i=1;i<=dcc;++i) fa[i]=i;
		read(t);
		int ans=dcc-1;
		printf("Case %d:\n",++T);
		while(t--){
			int x=c[read<int>()],y=c[read<int>()]; // edit 1: c[]
			int p=lca(x,y);
			x=get(x);
			while(d[x]>d[p]){
				fa[x]=f[x][0];
				--ans;
				x=get(x);
			}
			y=get(y);
			while(d[y]>d[p]){
				fa[y]=f[y][0];
				--ans;
				y=get(y);
			}
			printf("%d\n",ans);
		}
		puts("");
	}
	return 0;
}

posted on 2019-05-30 19:32  autoint  阅读(171)  评论(0编辑  收藏  举报

导航