Tarjan 割边+LCA+并查集优化(缩点)

// poj 3694

// 题意: 给一个N个点M条边所有点联通的无向图,问 Q此询问,每次增加一条u->v的无向边,输出每次增加后桥的数量

// N(1≤N≤100000) M(N-1≤M≤200000) Q(1≤Q≤1000)

// Time Limi:5000ms

// 割边+LCA 672ms(非并查集优化)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<map>
 4 #define rep(i, n) for(int i=0;i!=n;++i)
 5 #define rep1(i, n) for(int i=1;i<=n;++i)
 6 using namespace std;
 7 
 8 inline int read() {
 9     char c=getchar();int x=0,f=1;
10     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
11     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
12     return x*f;
13 }
14 // --------------------------------------------
15 const int MAXN = 100000+5;
16 const int MAXM = 402000+5;
17 
18 int num;
19 int head[MAXN];
20 struct node {
21     int v, next;
22 } edge[MAXM];
23 
24 inline void add(int x, int y) {
25     edge[num].v = y;
26     edge[num].next = head[x];
27     head[x] = num++;
28 }
29 
30 int n, m, q;
31 int cnt, ans;
32 int dfn[MAXN], low[MAXN], pre[MAXN], deep[MAXN];
33 bool bridge[MAXN];
34 
35 void Tarjan(int cur, int fa) {
36     dfn[cur] = low[cur] = ++cnt;
37     for(int i = head[cur]; i != -1; i = edge[i].next) {
38         int v = edge[i].v;
39         if(!dfn[v]) {
40             deep[v] = deep[cur] + 1;
41             pre[v] = cur;
42             Tarjan(v, cur);
43             low[cur] = min(low[cur], low[v]);
44             if(low[v] > dfn[cur]) bridge[v] = true, ++ans;// u->v是割边 用dridge[v]记录
45         }
46         else if(v != fa) low[cur] = min(low[cur], dfn[v]);// u!=fa 去重边
47     }
48 }
49 
50 int LCA(int x, int y) {// (大致思想)LCA的过程中减去x->Lca(x,y)->y中的桥
51     if(deep[x] < deep[y]) swap(x, y);
52     while(deep[x] != deep[y]) {
53         if(bridge[x]) --ans, bridge[x] = false;
54         x = pre[x];
55     }
56     while(x != y) {
57         if(bridge[x]) --ans, bridge[x] = false;
58         if(bridge[y]) --ans, bridge[y] = false;
59         x = pre[x]; y = pre[y];
60     }
61     return ans;
62 }
63 
64 void solve(int qaq) {
65     cnt = ans = 0;
66     rep1(i, n) bridge[i] = false;
67     rep1(i, n) dfn[i] = 0;
68     deep[1] = 1;
69     Tarjan(1, 0);
70     printf("Case %d:\n", qaq);
71     q = read();
72     int x, y;
73     rep(i, q) {
74         x = read(); y = read();
75         printf("%d\n", LCA(x, y));
76     }
77     printf("\n");
78 }
79 
80 int main() {
81     int qaq = 1;
82     while(scanf("%d%d", &n, &m) == 2 && n) {
83         num = 0;
84         rep1(i, n) head[i] = -1;
85         int x, y;
86         rep(i, m) {
87             x = read(); y = read();
88             add(x, y); add(y, x);
89         }
90         solve(qaq++);
91     }
92     return 0;
93 }

 

// 上述代码 并查集优化后 266ms(数据量小 不优化也挺快)

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<map>
  4 #define rep(i, n) for(int i=0;i!=n;++i)
  5 #define rep1(i, n) for(int i=1;i<=n;++i)
  6 using namespace std;
  7 
  8 inline int read() {
  9     char c=getchar();int x=0,f=1;
 10     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
 11     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
 12     return x*f;
 13 }
 14 // --------------------------------------------
 15 const int MAXN = 100000+5;
 16 const int MAXM = 402000+5;
 17 
 18 int num;
 19 int head[MAXN];
 20 struct node {
 21     int v, next;
 22 } edge[MAXM];
 23 
 24 inline void add(int x, int y) {
 25     edge[num].v = y;
 26     edge[num].next = head[x];
 27     head[x] = num++;
 28 }
 29 
 30 int n, m, q;
 31 int cnt, ans;
 32 int dfn[MAXN], low[MAXN], pre[MAXN];
 33 int fa[MAXN];
 34 
 35 inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
 36 
 37 inline void join(int x, int y) {
 38     int xf = find(x), yf = find(y);
 39     if(xf != yf) fa[xf] = yf;
 40 }
 41 
 42 void Tarjan(int cur, int prv) {
 43     dfn[cur] = low[cur] = ++cnt;
 44     for(int i = head[cur]; i != -1; i = edge[i].next) {
 45         int v = edge[i].v;
 46         if(!dfn[v]) {
 47             pre[v] = cur;
 48             Tarjan(v, cur);
 49             low[cur] = min(low[cur], low[v]);
 50             if(low[v] > dfn[cur]) ++ans;
 51             else join(cur, v);
 52         }
 53         else if(v != prv) low[cur] = min(low[cur], dfn[v]);
 54     }
 55 }
 56 
 57 inline void fn(int x) {
 58     int xf = find(x), yf = find(pre[x]);
 59     if(xf != yf) fa[xf] = yf, --ans;// 与父节点不在同一缩点中
 60 }
 61 
 62 void LCA(int x, int y) {
 63     if(dfn[x] < dfn[y]) swap(x, y);// 可以用deep[] 但是用dfn[]也行 思考🤔
 64     while(dfn[x] > dfn[y]) {
 65         fn(x);
 66         x = pre[x];
 67     }
 68     while(x != y) {
 69         fn(y);
 70         y = pre[y];
 71     }
 72 }
 73 
 74 void solve(int qaq) {
 75     cnt = ans = 0;
 76     rep1(i, n) dfn[i] = 0, fa[i] = i;
 77     Tarjan(1, 0);
 78     printf("Case %d:\n", qaq);
 79     q = read();
 80     int x, y;
 81     rep(i, q) {
 82         x = read(); y = read();
 83         if(find(x) != find(y)) LCA(x, y);// x和y 在同一缩点中 没有桥
 84         printf("%d\n", ans);
 85     }
 86     printf("\n");
 87 }
 88 
 89 int main() {
 90     int qaq = 1;
 91     while(scanf("%d%d", &n, &m) == 2 && n) {
 92         num = 0;
 93         rep1(i, n) head[i] = -1;
 94         int x, y;
 95         rep(i, m) {
 96             x = read(); y = read();
 97             add(x, y); add(y, x);
 98         }
 99         solve(qaq++);
100     }
101     return 0;
102 }

 

posted @ 2019-10-31 16:15  pupil337  阅读(220)  评论(0编辑  收藏  举报