标签:c++
题目链接:
题意:
给出一个N(1 ≤ N ≤ 100,000)个点 和 M(N - 1 ≤ M ≤ 200,000)的连通图.
有Q ( 1 ≤ Q ≤ 1,000)个询问 每次询问增加一条边(累加下去)
输出每增加一条边后剩下的桥的数量
题解:
10W点加1000次询问 每次询问都用Tarjin算法求一次肯定会超时的
考虑 每次加一条边a-b的实质:
从a到b的路径中的所有割边都将消失
那如何记录这条路径呢
在Tarjan算法递归的过程中通过树边建立一棵树
然后每次询问分别从a b开始 一直到它们的最近公共祖先 出现的割边全部消失即可
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #define maxn 100050 using namespace std; struct node{ int to,next; }edge[maxn*4]; int head[maxn]; int s; int dfn[maxn],low[maxn],num; int level[maxn],fa[maxn]; int flag[maxn]; int n,ans; void init() { memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(flag,0,sizeof(flag)); s=ans=num=0; level[0]=0; for(int i=1;i<=n;i++) fa[i]=i; } void addedge(int a,int b) { edge[s]={b,head[a]}; head[a]=s++; } void lca(int a,int b) { while(level[b]>level[a]) { if(flag[b]) ans--,flag[b]=0; b=fa[b]; } while(level[a]>level[b]) { if(flag[a]) ans--,flag[a]=0; a=fa[a]; } while(a!=b) { if(flag[a]) ans--,flag[a]=0; if(flag[b]) ans--,flag[b]=0; a=fa[a],b=fa[b]; } } void Tarjan(int u,int pre) { dfn[u]=low[u]=++num; level[u]=level[pre]+1; //建树 for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(!dfn[v]) { fa[v]=u; Tarjan(v,u); low[u]=min(low[u],low[v]); if(dfn[u]<low[v]) //标记割边 flag[v]=1,ans++; } if(v!=pre) low[u]=min(low[u],dfn[v]); } } int main() { int m,a,b; int Case=1; while(scanf("%d%d",&n,&m)&&(n+m)) { init(); while(m--) { scanf("%d%d",&a,&b); addedge(a,b); addedge(b,a); } Tarjan(1,0); scanf("%d",&m); printf("Case %d:\n",Case++); while(m--) { scanf("%d%d",&a,&b); if(ans!=0) lca(a,b); printf("%d\n",ans); } printf("\n"); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:c++
原文地址:http://blog.csdn.net/axuan_k/article/details/46778357