您的位置:首页 > 其它

poj 3694Network 双联通分量+lca

2016-05-18 17:29 260 查看
输入:

3 2

1 2

2 3

2

1 2

1 3

题意就是先输入n,m 表示一颗树有n个节点,m条无向边。然后又q次操作, 每一次操作 输入i,j 表示在节点i和节点j之间加一条边,并且询问在加边之后的图中存在多少个桥。

在这里先感谢大牛:

/article/6666420.html

他的博客真的给了我很多的帮助,在我犯了很多很多错误的时候 用很简短很清晰的代码拨正了我的错误思维。膜一发

这题 我一开始是这样写的: 先dfs 跑一发tarjan,把dfn,low 桥 连通块 都跑出来。 然后再 dfs 跑一发st的lca在线询问, 然后对于加边 i,j 我们就从i 向上遍历到 lca,从j 向上遍历到lca,扫描减少的桥的数量。 不知道是不是姿势写的太丑,还是两遍dfs耗时间,反正就是T了。 (现在想想 好像是因为 fa[i] 写的有问题才会T)

然后膜了一下别人的代码, 感觉至少比我的代码少 100 行 TUT,我好菜啊

感觉自己没有学懂tarjan啊,好菜啊,明明一遍dfs就可以做完,因为我们后面lca 用很朴素的想法的话用dfn和low就可以完成了,话不多说 上代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <typeinfo>
#include <fstream>
#include <map>
#include <stack>
typedef long long ll;
using namespace std;
const int N = 100010;//点数
const int MAXM = 200010;//边数,因为是无向图,所以这个值要*2

int head
,dfn
,low
,vis
,fa
,dcnt,bridge;
int isbri
;
struct Edge{
int u,v,next;
int used;  //判断是否为桥
int bri;
}edge[2*MAXM];
int tot;
void addedge(int u,int v){
edge[tot].v=v;
edge[tot].used=0;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs(int u,int pre){
//  printf("u=%d\n",u);
vis[u]=1;
dfn[u]=low[u]=++dcnt;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
//      if(v==pre) continue;
if(!edge[i].used){
edge[i].used=edge[i^1].used=1;
if(!vis[v]){
fa[v]=u;
dfs(v,u);
if( low[u] > low[v] )  low[u] = low[v];
if(low[v] > dfn[u]){   //桥
bridge++;
isbri[v]=1;  // 精妙: 只会设置每一条路的终点,反向并不会设置
}
}
else if(vis[u] && low[u]> dfn[v])
low[u]=dfn[v];
}
}
}
void LCA(int u,int v){ //重点来了, 其实LCA完全没必要再扫一遍,借助low 和 dfn 完全够实现lca

if(dfn[u] < dfn[v]) swap(u,v);  // dfn  即 深度
while(dfn[u] > dfn[v]){   //因为 u是较深的那个点,先尽量往上移动
if(isbri[u]) bridge--;
isbri[u]=0;
u=fa[u];
}
while(dfn[v]>dfn[u]){
if(isbri[v]) bridge--;
isbri[v]=0;
v=fa[v];
}
while(u!=v){
if(isbri[u]) bridge--;
if(isbri[v]) bridge--;
isbri[u]=isbri[v]=0;
u=fa[u];
v=fa[v];
}
//最后 u=v , 这个u就是lca,但我不说
//讲道理  复杂度有点高啊
}
bool flag
;
void init(){
tot=0;
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
memset(isbri,0,sizeof(isbri));
memset(flag,0,sizeof(flag));
dcnt = bridge = 0;
}
int main(){
// freopen("1.txt","r",stdin);
int n,m,cas=0;
while(~scanf("%d %d",&n,&m) && (n||m)){
init();
printf("Case %d:\n",++cas);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d %d",&u,&v);
addedge(u,v);
addedge(v,u);
flag[v]=true;
}
dfs(1,1);
int q;
//      printf("bri=%d\n",bridge);
//      for(int i=1;i<=n;i++){
//          printf("%d ",dfn[i]);
//      }
//        cout<<endl;
scanf("%d",&q);
while(q--){
int a,b;
scanf("%d %d",&a,&b);
if(bridge==0){
printf("0\n");
continue;
}
LCA(a,b);
printf("%d\n",bridge);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: