题目描述
传送门
题意:首先给出一个无向图。每一次询问向这个图里加一条边,求加了这条边之后图中的桥的个数。
题解
首先tarjan将所有的双连通分量缩成一个点,形成一棵树,每一条树边都是桥边。每连一条边实际上是将这条树链上的所有边都变成非桥边。可以用树链剖分来实现。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 200005
int n,m,q,x,y,dfs_clock,dcc,ans,Case;
int tot,point[N],v[N*2],nxt[N*2];
int dfn[N],low[N],stack[N],tmp,belong[N];
int father[N],h[N],size[N],num[N],son[N],top[N];
int sum[N*4],delta[N*4];
bool vis[N];
struct hp{int x,y;}e[N];
void clear()
{
q=x=y=dfs_clock=dcc=ans=0;
tot=0;memset(point,0,sizeof(point));memset(nxt,0,sizeof(nxt));memset(v,0,sizeof(v));
memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(belong,0,sizeof(belong));tmp=0;
memset(father,0,sizeof(father));memset(h,0,sizeof(h));memset(size,0,sizeof(size));memset(num,0,sizeof(num));
memset(son,0,sizeof(son));memset(top,0,sizeof(top));memset(sum,0,sizeof(sum));memset(delta,0,sizeof(delta));
memset(vis,0,sizeof(vis));
}
void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++dfs_clock;vis[x]=true;stack[++tmp]=x;
bool flag=false;
for (int i=point[x];i;i=nxt[i])
{
if (v[i]==fa&&!flag)
{
flag=true;
continue;
}
if (!dfn[v[i]])
{
tarjan(v[i],x);
low[x]=min(low[x],low[v[i]]);
}
else if (vis[v[i]]) low[x]=min(low[x],low[v[i]]);
}
if (dfn[x]==low[x])
{
dcc++;int now=0;
while (now!=x)
{
now=stack[tmp--];
vis[now]=false;
belong[now]=dcc;
}
}
}
void rebuild()
{
tot=0;memset(point,0,sizeof(point));
for (int i=1;i<=m;++i)
if (belong[e[i].x]!=belong[e[i].y])
add(belong[e[i].x],belong[e[i].y]);
}
void dfs_1(int x,int fa,int dep)
{
father[x]=fa;h[x]=dep;size[x]=1;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
dfs_1(v[i],x,dep+1);
size[x]+=size[v[i]];
if (size[v[i]]>size[son[x]]) son[x]=v[i];
}
}
void dfs_2(int x,int fa)
{
if (son[fa]==x) top[x]=top[fa];
else top[x]=x;
num[x]=++dfs_clock;
if (son[x]) dfs_2(son[x],x);
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa&&v[i]!=son[x])
dfs_2(v[i],x);
}
void update(int now)
{
sum[now]=sum[now<<1]+sum[now<<1|1];
}
void pushdown(int now,int l,int r,int mid)
{
if (delta[now]!=-1)
{
sum[now<<1]=sum[now<<1|1]=delta[now<<1]=delta[now<<1|1]=0;
delta[now]=-1;
}
}
void build(int now,int l,int r)
{
int mid=(l+r)>>1;
delta[now]=-1;
if (l==r)
{
sum[now]=1;
return;
}
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}
void cover(int now,int l,int r,int lrange,int rrange)
{
int mid=(l+r)>>1;
if (lrange<=l&&r<=rrange)
{
sum[now]=delta[now]=0;
return;
}
pushdown(now,l,r,mid);
if (lrange<=mid) cover(now<<1,l,mid,lrange,rrange);
if (mid+1<=rrange) cover(now<<1|1,mid+1,r,lrange,rrange);
update(now);
}
int query(int now,int l,int r,int lrange,int rrange)
{
int mid=(l+r)>>1,ans=0;
if (lrange<=l&&r<=rrange) return sum[now];
pushdown(now,l,r,mid);
if (lrange<=mid) ans+=query(now<<1,l,mid,lrange,rrange);
if (mid+1<=rrange) ans+=query(now<<1|1,mid+1,r,lrange,rrange);
return ans;
}
void Cover(int u,int t)
{
int f1=top[u],f2=top[t];
while (f1!=f2)
{
if (h[f1]<h[f2])
{
swap(f1,f2);
swap(u,t);
}
cover(1,1,dcc,num[f1],num[u]);
u=father[f1];
f1=top[u];
}
if (num[u]==num[t]) return;
if (num[u]>num[t]) swap(u,t);
cover(1,1,dcc,num[u]+1,num[t]);
}
int Query(int u,int t)
{
int f1=top[u],f2=top[t],ans=0;
while (f1!=f2)
{
if (h[f1]<h[f2])
{
swap(f1,f2);
swap(u,t);
}
ans+=query(1,1,dcc,num[f1],num[u]);
u=father[f1];
f1=top[u];
}
if (num[u]==num[t]) return ans;
if (num[u]>num[t]) swap(u,t);
ans+=query(1,1,dcc,num[u]+1,num[t]);
return ans;
}
int main()
{
while (~scanf("%d%d",&n,&m))
{
if (!n&&!m) break;
printf("Case %d:\n",++Case);
clear();
for (int i=1;i<=m;++i)
{
scanf("%d%d",&e[i].x,&e[i].y);
add(e[i].x,e[i].y);
}
for (int i=1;i<=n;++i)
if (!dfn[i]) tarjan(i,0);
rebuild();ans=dcc-1;dfs_clock=0;
dfs_1(1,0,1);
dfs_2(1,0);
build(1,1,dcc);
scanf("%d",&q);
for (int i=1;i<=q;++i)
{
scanf("%d%d",&x,&y);
if (belong[x]==belong[y]) {printf("%d\n",ans);continue;}
ans-=Query(belong[x],belong[y]);
Cover(belong[x],belong[y]);
printf("%d\n",ans);
}
puts("");
}
}
手工栈
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 200005
int n,m,q,x,y,dfs_clock,dcc,ans,Case;
int tot,point[N],v[N*2],nxt[N*2];
int dfn[N],low[N],stack[N],tmp,belong[N];
int father[N],h[N],size[N],num[N],son[N],top[N];
int sum[N*4],delta[N*4];
bool vis[N];
struct hp{int x,y;}e[N];
int cur[N];bool use[N];
void clear()
{
q=x=y=dfs_clock=dcc=ans=0;
tot=0;memset(point,0,sizeof(point));memset(nxt,0,sizeof(nxt));memset(v,0,sizeof(v));
memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(belong,0,sizeof(belong));tmp=0;
memset(father,0,sizeof(father));memset(h,0,sizeof(h));memset(size,0,sizeof(size));memset(num,0,sizeof(num));
memset(son,0,sizeof(son));memset(top,0,sizeof(top));memset(sum,0,sizeof(sum));memset(delta,0,sizeof(delta));
memset(vis,0,sizeof(vis));
memset(cur,0,sizeof(cur));memset(use,0,sizeof(use));
}
void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++dfs_clock;vis[x]=true;stack[++tmp]=x;
bool flag=false;
for (int i=point[x];i;i=nxt[i])
{
if (v[i]==fa&&!flag)
{
flag=true;
continue;
}
if (!dfn[v[i]])
{
tarjan(v[i],x);
low[x]=min(low[x],low[v[i]]);
}
else if (vis[v[i]]) low[x]=min(low[x],low[v[i]]);
}
if (dfn[x]==low[x])
{
dcc++;int now=0;
while (now!=x)
{
now=stack[tmp--];
vis[now]=false;
belong[now]=dcc;
}
}
}
void rebuild()
{
tot=0;memset(point,0,sizeof(point));
for (int i=1;i<=m;++i)
if (belong[e[i].x]!=belong[e[i].y])
add(belong[e[i].x],belong[e[i].y]);
}
void dfs_1()
{
int tmp=0;
stack[++tmp]=1;h[1]=1;size[1]=1;
for (int i=1;i<=n;++i) cur[i]=point[i];
while (tmp)
{
int x=stack[tmp];
if (cur[x]&&v[cur[x]]==father[x]) cur[x]=nxt[cur[x]];
if (!cur[x])
{
--tmp;
if (father[x])
{
size[father[x]]+=size[x];
if (size[x]>size[son[father[x]]]) son[father[x]]=x;
}
continue;
}
int vt=v[cur[x]];
stack[++tmp]=vt;
size[vt]=1;h[vt]=h[x]+1;father[vt]=x;
cur[x]=nxt[cur[x]];
}
}
void dfs_2()
{
int tmp=0;
stack[++tmp]=1;num[1]=++dfs_clock;top[1]=1;
for (int i=1;i<=n;++i) cur[i]=point[i];
while (tmp)
{
int x=stack[tmp];
if (!use[x])
{
use[x]=1;
int vt=son[x];
if (vt)
{
stack[++tmp]=vt;
top[vt]=top[x];
num[vt]=++dfs_clock;
}
continue;
}
while (cur[x]&&(v[cur[x]]==father[x]||v[cur[x]]==son[x])) cur[x]=nxt[cur[x]];
if (!cur[x])
{
--tmp;
continue;
}
else
{
int vt=v[cur[x]];
stack[++tmp]=vt;
num[vt]=++dfs_clock;
top[vt]=vt;
cur[x]=nxt[cur[x]];
}
}
}
void update(int now)
{
sum[now]=sum[now<<1]+sum[now<<1|1];
}
void pushdown(int now,int l,int r,int mid)
{
if (delta[now]!=-1)
{
sum[now<<1]=sum[now<<1|1]=delta[now<<1]=delta[now<<1|1]=0;
delta[now]=-1;
}
}
void build(int now,int l,int r)
{
int mid=(l+r)>>1;
delta[now]=-1;
if (l==r)
{
sum[now]=1;
return;
}
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}
void cover(int now,int l,int r,int lrange,int rrange)
{
int mid=(l+r)>>1;
if (lrange<=l&&r<=rrange)
{
sum[now]=delta[now]=0;
return;
}
pushdown(now,l,r,mid);
if (lrange<=mid) cover(now<<1,l,mid,lrange,rrange);
if (mid+1<=rrange) cover(now<<1|1,mid+1,r,lrange,rrange);
update(now);
}
int query(int now,int l,int r,int lrange,int rrange)
{
int mid=(l+r)>>1,ans=0;
if (lrange<=l&&r<=rrange) return sum[now];
pushdown(now,l,r,mid);
if (lrange<=mid) ans+=query(now<<1,l,mid,lrange,rrange);
if (mid+1<=rrange) ans+=query(now<<1|1,mid+1,r,lrange,rrange);
return ans;
}
void Cover(int u,int t)
{
int f1=top[u],f2=top[t];
while (f1!=f2)
{
if (h[f1]<h[f2])
{
swap(f1,f2);
swap(u,t);
}
cover(1,1,dcc,num[f1],num[u]);
u=father[f1];
f1=top[u];
}
if (num[u]==num[t]) return;
if (num[u]>num[t]) swap(u,t);
cover(1,1,dcc,num[u]+1,num[t]);
}
int Query(int u,int t)
{
int f1=top[u],f2=top[t],ans=0;
while (f1!=f2)
{
if (h[f1]<h[f2])
{
swap(f1,f2);
swap(u,t);
}
ans+=query(1,1,dcc,num[f1],num[u]);
u=father[f1];
f1=top[u];
}
if (num[u]==num[t]) return ans;
if (num[u]>num[t]) swap(u,t);
ans+=query(1,1,dcc,num[u]+1,num[t]);
return ans;
}
int main()
{
while (~scanf("%d%d",&n,&m))
{
if (!n&&!m) break;
printf("Case %d:\n",++Case);
clear();
for (int i=1;i<=m;++i)
{
scanf("%d%d",&e[i].x,&e[i].y);
add(e[i].x,e[i].y);
}
for (int i=1;i<=n;++i)
if (!dfn[i]) tarjan(i,0);
rebuild();ans=dcc-1;dfs_clock=0;
dfs_1();
dfs_2();
build(1,1,dcc);
scanf("%d",&q);
for (int i=1;i<=q;++i)
{
scanf("%d%d",&x,&y);
if (belong[x]==belong[y]) {printf("%d\n",ans);continue;}
ans-=Query(belong[x],belong[y]);
Cover(belong[x],belong[y]);
printf("%d\n",ans);
}
puts("");
}
}