poj3694(tarjan缩点+lca)
2015-02-08 11:54
302 查看
传送门:Network
题意:给你一个连通图,然后再给你n个询问,每个询问给一个点u,v表示加上u,v之后又多少个桥。
分析:方法(1219ms):用并查集缩点,把不是桥的点缩成一个点,然后全图都是桥,每次加边的两个点如果是缩后的同个点,必定不是桥,否则是桥,再把它们到达lca之间的点缩成一点。
方法2(A巨思路360ms):先一次tarjan缩点,重新建图得到一颗树,每次加边,两个端点到它们的lca之间的边都不再是桥,所以每一次我们都可以通过暴力求出lca,然后统计出少了多少条桥,但是暴力统计时,会遇到某些边在之前就不是桥的情况,我们用并查集来跳过这些边(每一次加边就把lca路径上的点都合并到一个集合里去,这里根用最上面的点,到时如果遇到这种点,直接可以跳到它们的根上去)
方法1:
View Code
题意:给你一个连通图,然后再给你n个询问,每个询问给一个点u,v表示加上u,v之后又多少个桥。
分析:方法(1219ms):用并查集缩点,把不是桥的点缩成一个点,然后全图都是桥,每次加边的两个点如果是缩后的同个点,必定不是桥,否则是桥,再把它们到达lca之间的点缩成一点。
方法2(A巨思路360ms):先一次tarjan缩点,重新建图得到一颗树,每次加边,两个端点到它们的lca之间的边都不再是桥,所以每一次我们都可以通过暴力求出lca,然后统计出少了多少条桥,但是暴力统计时,会遇到某些边在之前就不是桥的情况,我们用并查集来跳过这些边(每一次加边就把lca路径上的点都合并到一个集合里去,这里根用最上面的点,到时如果遇到这种点,直接可以跳到它们的根上去)
方法1:
#include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #define LL long long #define mod 100000000 #define inf 0x3f3f3f3f #define eps 1e-6 #define N 100010 #define FILL(a,b) (memset(a,b,sizeof(a))) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define PII pair<int,int> using namespace std; struct edge { int v,next; edge(){} edge(int v,int next):v(v),next(next){} }e1[N<<2],e2[N<<2]; int n,scc,step,top,tot1,tot2; int head1 ,head2 ,dfn ,low ,belong ,Stack ; int deep ,fa ,pre ; bool instack ,vis[N<<2]; void init() { tot1=0;tot2=0;step=0;scc=0;top=0; FILL(head1,-1);FILL(head2,-1); FILL(low,0);FILL(dfn,0); FILL(instack,false);FILL(vis,0); } void addedge1(int u,int v) { e1[tot1]=edge(v,head1[u]); head1[u]=tot1++; } void addedge2(int u,int v) { e2[tot2]=edge(v,head2[u]); head2[u]=tot2++; } void tarjan(int u) { int v; dfn[u]=low[u]=++step; Stack[top++]=u; instack[u]=true; for(int i=head1[u];~i;i=e1[i].next) { v=e1[i].v; if(vis[i])continue; vis[i]=vis[i^1]=1; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) { low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]) { scc++; do { v=Stack[--top]; instack[v]=false; belong[v]=scc; }while(v!=u); } } void dfs_dep(int u,int f,int dep) { pre[u]=f;deep[u]=dep; for(int i=head2[u];~i;i=e2[i].next) { int v=e2[i].v; if(v==f)continue; dfs_dep(v,u,dep+1); } } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } int LCA(int u,int v) { while(u!=v) { if(deep[u]>=deep[v]&&u!=v) { u=pre[u]; } if(deep[v]>=deep[u]&&u!=v) { v=pre[v]; } u=find(u); v=find(v); } return u; } void solve() { for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); for(int u=1;u<=n;u++) { for(int i=head1[u];~i;i=e1[i].next) { int v=e1[i].v; if(belong[v]!=belong[u]) { addedge2(belong[u],belong[v]); } } } dfs_dep(1,1,0); for(int i=1;i<=scc;i++)fa[i]=i; int ans=scc-1,q,u,v; scanf("%d",&q); while(q--) { scanf("%d%d",&u,&v); int a=find(belong[u]); int b=find(belong[v]); int lca=LCA(a,b); while(a!=b) { if(deep[a]>=deep[b]&&a!=b) { ans--; fa[a]=lca; a=pre[a]; } if(deep[b]>=deep[a]&&a!=b) { ans--; fa[b]=lca; b=pre[b]; } a=find(a); b=find(b); } printf("%d\n",ans); } } int main() { int m,u,v,cas=1; while(scanf("%d%d",&n,&m)&&(n||m)) { init(); for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); addedge1(u,v); addedge1(v,u); } printf("Case %d:\n",cas++); solve(); } }
View Code
相关文章推荐
- POJ3694-Network(Tarjan缩点+LCA)
- Tarjan缩点+LCA【p2783】有机化学之神偶尔会做作弊
- 连通分量模板:tarjan: 求割点 && 桥 && 缩点 && 强连通分量 && 双连通分量 && LCA(近期公共祖先)
- poj3694 Network 【图论-Tarjan-Lca】
- poj3694+hdu2460 求桥+缩点+LCA/tarjan
- POJ3694 Network(求桥的数目,lca,Tarjan)
- poj3694+hdu2460 求桥+缩点+LCA/tarjan
- 连通分量模板:tarjan: 求割点 && 桥 && 缩点 && 强连通分量 && 双连通分量 && LCA(最近公共祖先)
- POJ3694-Network(Tarjan缩点+LCA)
- poj3694 Network 求桥边个数[tarjan + LCA]
- poj3694(lca + tarjan求桥模板)
- Tarjan缩点+LCA【洛谷P2416】 泡芙
- poj3694 Network 边双联通缩点+离线LCA
- POJ 1986 LCA,tarjan实现
- Bridges Gym - 100712H 无向图的边双连通分量,Tarjan缩点
- J. City traffic tarjan缩点 11TH BUPT Collegiate Programming Contest
- hdu 1827 Summer Holiday tarjan 加缩点
- 模板_tarjan强连通缩点算法
- POJ 3352 Road Construction POJ 3177Redundant Paths(Tarjan缩点)
- pku Nearest Common Ancestors LCA 问题(rmq && tarjan)解决