求桥,缩点,LCA,还有重边,之后还要加Q条边,每次加完后询问一次桥的个数。。。个人感觉算是比较麻烦的题了。。。
给出N个点,M条边,保证所有点连通,数据中有重边,之后加入Q条边,每次加完后,输出一个整数代表图中剩余的桥的数量。
首先找出所有的桥,将桥删除,然后将双连通分量进行缩点,用桥将这些点连接起来,然后用LCA处理。
对于每条新加入的边,首先判断其两端点被缩进了哪个点,设其分别被缩进了 u, v。
则因这条边而消除的桥,必为 [ LCA(u,v) , u ] 和 [ LCA(u,v) , v ]两条路上的桥。
桥与双连通分量的求法:
http://blog.csdn.net/zmx354/article/details/18503659
http://blog.csdn.net/zmx354/article/details/18076975
#include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #include <algorithm> #define LL long long #define PI (acos(-1.0)) #define EPS (1e-10) using namespace std; const int MAXN = 100010; struct N { int v,next; }Edge[MAXN*4],Lca_Edge[MAXN*4]; struct E { int u,v; }Bridge[MAXN*2]; int Top_Edge,Top_Bridge,Lca_Top_Edge,Lca_Time; int head[MAXN]; int Lca_Head[MAXN]; int mv[MAXN]; int depth[MAXN]; int Lca_Depth[MAXN]; int Lca_Vis[MAXN]; int Point[MAXN*2]; int st[MAXN*8]; int father[MAXN]; int root[MAXN]; bool Cut[MAXN]; void link(int u,int v) { Edge[++Top_Edge].v = v; Edge[Top_Edge].next = head[u]; head[u] = Top_Edge; } void Lca_Link(int u,int v) { Lca_Edge[++Lca_Top_Edge].v = v; Lca_Edge[Lca_Top_Edge].next = Lca_Head[u]; Lca_Head[u] = Lca_Top_Edge; } int Find(int x) { while(x != father[x]) x = father[x]; return x; } void Merge(int u,int v) { int fu = Find(u); int fv = Find(v); if(fu != fv) { father[fu] = fv; } } int Dfs(int s,int f,int h) { mv[s] = 1;//表示灰色,即已开始DFS且正在等待回溯 depth[s] = h; int p,Temp_Depth,Min_Depth = MAXN; bool Cover = false; for(p = head[s];p != -1;p = Edge[p].next) { if(Edge[p].v != f || Cover) { if(mv[Edge[p].v] == 0) { Temp_Depth = Dfs(Edge[p].v,s,h+1); if(Temp_Depth < Min_Depth) Min_Depth = Temp_Depth; } else if(mv[Edge[p].v] == 1) { if(depth[Edge[p].v] < Min_Depth) Min_Depth = depth[Edge[p].v]; } } else Cover = true; } if(f != -1 && Min_Depth >= depth[s]) { Bridge[Top_Bridge].u = f; Bridge[Top_Bridge].v = s; Top_Bridge++; } else if(f != -1) { Merge(f,s); } return Min_Depth; } void Lca_Dfs(int s,int h) { Lca_Depth[s] = h; Point[Lca_Time] = s; Lca_Vis[s] = Lca_Time++; for(int p = Lca_Head[s]; p != -1; p = Lca_Edge[p].next) { if(Lca_Vis[Lca_Edge[p].v] == -1) { root[Lca_Edge[p].v] = s; Cut[Lca_Edge[p].v] = false; Lca_Dfs(Lca_Edge[p].v,h+1); Point[Lca_Time++] = s; } } } void Init_St(int site,int l,int r) { if(l == r) { st[site] = Lca_Depth[Point[l]]; return ; } int mid = (l+r)>>1; Init_St(site<<1,l,mid); Init_St(site<<1|1,mid+1,r); if(st[site<<1] < st[site<<1|1]) st[site] = st[site<<1]; else st[site] = st[site<<1|1]; } int Query_St(int site,int L,int R,int l,int r) { if(l == L && R == r) { return st[site]; } int mid = (L+R)>>1; if(mid < l) { return Query_St(site<<1|1,mid+1,R,l,r); } else if(r <= mid) { return Query_St(site<<1,L,mid,l,r); } int h1 = Query_St(site<<1,L,mid,l,mid); int h2 = Query_St(site<<1|1,mid+1,R,mid+1,r); return (h1 < h2 ? h1 : h2); } int Query(int u,int v) { int h; if(Lca_Vis[u] < Lca_Vis[v]) h = Query_St(1,0,Lca_Time-1,Lca_Vis[u],Lca_Vis[v]); else h = Query_St(1,0,Lca_Time-1,Lca_Vis[v],Lca_Vis[u]); int i,f,ans = 0; //cout<<"h = "<<h<<" ans = "<<ans<<endl; for(i = h,f = u;i < Lca_Depth[u]; ++i) { if(Cut[f] == false) { ans++; Cut[f] = true; f = root[f]; } } for(i = h,f = v;i < Lca_Depth[v]; ++i) { if(Cut[f] == false) { ans++; Cut[f] = true; f = root[f]; } } //cout<<"ans = "<<ans<<endl; return ans; } int main() { int n,m,i,u,v,fu,fv; int icase = 1; while(scanf("%d %d",&n,&m) != EOF && (n||m)) { Top_Bridge = 0,Top_Edge = -1,Lca_Top_Edge = -1,Lca_Time = 0; memset(head,-1,sizeof(int)*(n+2)); memset(mv,0,sizeof(int)*(n+2));//表示白色,即未进行DFS memset(Lca_Head,-1,sizeof(int)*(n+2)); memset(Lca_Vis,-1,sizeof(int)*(n+2)); for(i = 1;i <= n; ++i) { father[i] = i; } for(i = 0;i < m; ++i) { scanf("%d %d",&u,&v); link(u,v); link(v,u); } //计算双连通分量 Dfs(1,-1,1); //cout<<"Top = "<<Top_Bridge<<endl; for(i = 0;i < Top_Bridge; ++i) { fu = Find(Bridge[i].u); fv = Find(Bridge[i].v); Lca_Link(fu,fv); Lca_Link(fv,fu); } //计算LCA Lca_Dfs(Find(1),1); //初始化线段书 Init_St(1,0,Lca_Time-1); scanf("%d",&m); printf("Case %d:\n",icase++); while(m--) { scanf("%d %d",&u,&v); Top_Bridge = Top_Bridge - Query(Find(u),Find(v)); printf("%d\n",Top_Bridge); } printf("\n"); } return 0; }