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;
}
静渊以有谋,疏通而知事。