版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/82944048
题目:PO3694.
题目大意:给出一张图,然后给出Q组连接操作,输出每一次操作后的割边(桥)数量.
注:这道题给出的图是连通图.
首先这道题可以先用tarjan缩点,我们可以得出一棵树,这棵树上的每一条边都是割边.
之后每一次加边,若加入的边在一个点内,则直接跳过.
否则我们设这条边的两个顶点所在的树上节点为u和v,我们发现u到v路径上的所有边都不再是割边,所以我们将所有在u到v的路径上的点暴力缩到一个点内,这样做的时间复杂度为的.由于这道题时限宽松,这个做法可以过.
暴力缩点的时候我们先暴力求出LCA,然后我们可以分别处理两条链,并将所有链上的点的标记打上LCA的标记(但是我直接写并査集了不展示了,我才不会告诉你其实是我写的暴力挂了...).
但是这个做法还可以优化,我们发现图一定是连通,所以缩完的树连边一定不会将两棵树并为一棵,所以我们可以用并查集来维护这个问题,时间复杂度.
所以我们可以先tarjan缩点建树,然后每一次询问倍增求出LCA,并将链用并査集合并.注意这里的倍增求出LCA与并査集合并并不冲突,我们维护的其实是两棵树,一棵是静态的树,用于倍增求LCA,一棵是动态的树,用并査集来维护.
代码如下:
//#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
using namespace std;
#define Abigail inline void
const int N=100000,M=200000;
int n,m;
struct graph_side{
int y,next;
bool br;
}e[M*2+9];
int lin[N+9],t;
int dfn[N+9],low[N+9],edcc[N+9],dcc,num,ans;
struct tree_side{
int y,next;
}ec[N*2+9];
int linc[N+9],tc;
int deep[N+9],gr[N+9][19];
int fa[N+9];
void ins(int x,int y){
e[++t].y=y;
e[t].next=lin[x];
lin[x]=t;
}
void insc(int x,int y){
ec[++tc].y=y;
ec[tc].next=linc[x];
linc[x]=tc;
}
void tarjan(int k,int fa){
dfn[k]=low[k]=++num;
for (int i=lin[k];i;i=e[i].next){
int y=e[i].y;
if (!dfn[y]){
tarjan(y,i);
low[k]=min(low[k],low[y]);
if (low[y]>dfn[k]) e[i].br=e[i^1].br=1;
}else if (i^fa^1) low[k]=min(low[k],dfn[y]);
}
}
void dfs(int k){
edcc[k]=dcc;
for (int i=lin[k];i;i=e[i].next)
if (!edcc[e[i].y]&&!e[i].br) dfs(e[i].y);
}
void contract(){
for (int i=1;i<=n;i++)
if (!dfn[i]) tarjan(i,0);
for (int i=1;i<=n;i++)
if (!edcc[i]) ++dcc,dfs(i);
for (int i=2;i<=t;i++){
int x=e[i^1].y,y=e[i].y;
if (edcc[x]==edcc[y]) continue;
insc(edcc[x],edcc[y]);
}
}
void dfs_lca(int k,int fa){
deep[k]=deep[fa]+1;
gr[k][0]=fa;
for (int i=1;i<19;i++)
gr[k][i]=gr[gr[k][i-1]][i-1];
for (int i=linc[k];i;i=ec[i].next)
if (ec[i].y^fa) dfs_lca(ec[i].y,k);
}
int LCA(int x,int y){
if (deep[x]<deep[y]) swap(x,y);
for (int i=18;i>=0;i--)
if (deep[gr[x][i]]>=deep[y]) x=gr[x][i];
if (x==y) return x;
for (int i=18;i>=0;i--)
if (gr[x][i]^gr[y][i]) x=gr[x][i],y=gr[y][i];
return gr[x][0];
}
int get(int u){
return u^fa[u]?fa[u]=get(fa[u]):u;
}
void access(int from,int to){
from=get(from);
while (deep[from]>deep[to]){
fa[from]=gr[from][0];
ans--;
from=get(from);
}
}
Abigail start(){
t=tc=1;num=dcc=0;
for (int i=1;i<=n;i++)
linc[i]=lin[i]=dfn[i]=low[i]=edcc[i]=deep[i]=0;
for (int i=1;i<=2*m+1;i++)
e[i].br=e[i].y=e[i].next=ec[i].y=ec[i].next=0;
}
Abigail into(){
int x,y;
for (int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
ins(x,y);ins(y,x);
}
}
Abigail work(){
contract();
dfs_lca(1,0);
for (int i=1;i<=dcc;i++) fa[i]=i;
}
Abigail getans(int cas){
int q,x,y;ans=dcc-1;
printf("Case %d:\n",cas);
scanf("%d",&q);
for (int i=1;i<=q;i++){
scanf("%d%d",&x,&y);
x=edcc[x],y=edcc[y];
int lca=LCA(x,y);
access(x,lca);access(y,lca);
printf("%d\n",ans);
}
printf("\n");
}
int main(){
for (int cas=1;~scanf("%d%d",&n,&m)&&n+m;cas++){
start();
into();
work();
getans(cas);
}
return 0;
}