1. 程式人生 > >poj 3694 Network

poj 3694 Network

new ret esp iostream void space 數量 std namespace

Description:

給定一張n節點m條邊的無向圖,執行Q次操作,每次加一條無向邊,詢問當前橋的數量

思路:先雙聯通縮點,然後得到一棵樹,對(x,y)連邊的時候暴力LCA一下 然後將路徑上的點用並查集全都壓到LCA上,這樣的話下次再搜到被壓了的點就可以直接跳到LCA上了,向上壓點的同時減去邊的數量

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 100050;
const int M = 200050;

int
head[N],now; struct edges{ int to,next; }edge[M<<1]; void add(int u,int v){ edge[++now] = {v,head[u]}; head[u] = now;} int n,m,low[N],dfn[N],tot,cnt,fa[N],pre[N],dep[N],dict[N],ans; bool bridge[M<<1]; struct input{ int x,y; }inp[M]; void init(){ for(int i = 1
; i <= n; i++) fa[i] = i; memset(inp,0,sizeof(inp)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); cnt = tot = 0; memset(pre,0,sizeof(pre)); memset(bridge,0,sizeof(bridge)); memset(head,0,sizeof(head)); memset(edge,0,sizeof(edge)); now = 1; memset(dep,0,sizeof
(dep)); memset(dict,0,sizeof(dict)); } void tarjan(int x,int in_edge){ //邊-雙聯通分量縮點 low[x] = dfn[x] = ++cnt; for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(!dfn[v]){ tarjan(v,i); low[x] = min(low[x],low[v]); if(low[v] > dfn[x]) bridge[i] = bridge[i ^ 1] = 1; } else if(i != (in_edge ^ 1)) low[x] = min(low[x],dfn[v]); } return ; } void dfs(int x){ dict[x] = tot; for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(dict[v] || bridge[i]) continue; dfs(v); } return ; } void new_dfs(int x){ for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(pre[x] == v) continue; dep[v] = dep[x] + 1; pre[v] = x; new_dfs(v); } } int get(int x){ if(x != fa[x]) return fa[x] = get(fa[x]); return x; } int lca(int u,int v){ while(u != v){ if(dep[u] > dep[v]) u = pre[u]; else if(dep[u] < dep[v]) v = pre[v]; else{ u = pre[u]; v = pre[v]; } u = get(u),v = get(v); } return u; } int main(){ // freopen("data.out","r",stdin); int kase = 0, q; while(scanf("%d%d",&n,&m)!= EOF && n + m){ init(); int x,y; for(int i = 1; i <= m ; i++){ scanf("%d%d",&x,&y); inp[i] = {x,y}; add(x,y); add(y,x); } tarjan(1,0); for(int i = 1; i <= n; i++) if(!dict[i]) tot++, dfs(i); memset(head,0,sizeof(head)); memset(edge,0,sizeof(edge)); now = 0; for(int i = 1; i <= m; i++) //縮點後得到新圖 if(dict[inp[i].x] != dict[inp[i].y]) add(dict[inp[i].x],dict[inp[i].y]),add(dict[inp[i].y],dict[inp[i].x]); new_dfs(1);//記錄每個點的父節點 scanf("%d",&q); printf("Case %d:\n",++kase); ans = tot - 1; while(q--){ scanf("%d%d",&x,&y); x = get(dict[x]), y = get(dict[y]); int tmp = lca(x,y); while(x != tmp){ //將x的所有沒有壓到xy的LCA的點全都壓到LCA上 ans--; fa[x] = tmp; x = get(pre[x]); } while(y != tmp){ //同上 ans--; fa[y] = tmp; y = get(pre[y]); } printf("%d\n",ans); } puts(""); } return 0; }

poj 3694 Network