Hdu 5458 Stability (LCA + 并查集 + 树状数组 + 缩点)

题目链接:

  Hdu 5458 Stability

题目描述:

  给出一个还有环和重边的图G,对图G有两种操作:

  1 u v, 删除u与v之间的一天边 (保证这个边一定存在)

  2 u v, 查询u到v的路径上有几条桥。

解题思路:

  这个题目有很多次操作,包含查询和删边两类,首先想到的是连通分量加缩点。如果按照顺序来,删边时候求桥就是问题了。所以可以离线处理,然后一边记录答案一边加边缩点。

  对于一个图,把连通分量缩成一个点后,这个图就成为了一棵树, 然后深度差就等于桥的数目。查询的时候对于(u, v)桥的数目等于(设定deep[x]为x的深度,LCA(x, y)为(x, y)的父节点) deep[u] + deep[v] - 2 * deep[LCA(u, v)];

  现在问题就成了怎么才能更快的缩点和维护点的深度。

  缩点问题:在树上加上一条边就会形成一个环,然后这个环(强连通分量)上点就会被缩成一个点,然后用并查集来维护强联通分量,每次只需要合并父节点(每个点只能被缩一次,复杂度被平摊还是很可观的)

  维护节点深度:每次儿子节点合并到父亲节点的时候,儿子节点的子孙节点的深度都要减一。在这里我们可以用dfs序 + 树状数组来维护节点的深度。利用树状数组的区间更改点查询优化维护深度的操作。

  还有最后一个问题就是计算(u, v)节点之间桥数目的时候,需要用到LCA,可以利用树上倍增LCA来优化时间复杂度。

这个题目还是很值得本扎扎练手的,考察了很多东西,真是把压箱底的东西都翻出来晒了晒,仰慕当场ac的聚聚们。

  1 #include <vector>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 using namespace std;
  7 const int maxn = 30010;
  8 const int N = 100010;
  9 const int M = 16;
 10 
 11 struct node
 12 {
 13     int to, del;
 14     node(int x):to(x),del(0) {}
 15     bool operator < (const node & a) const
 16     {
 17         if (to != a.to) return to < a.to;
 18         return del > a.del;
 19     }
 20 };
 21 vector <node> vec[maxn];
 22 
 23 struct Query
 24 {
 25     int op, u, v;
 26     void read ()
 27     {
 28         scanf ("%d %d %d", &op, &u, &v);
 29         if (op == 1)
 30         {
 31             lower_bound (vec[u].begin(), vec[u].end(), node(v)) -> del = true;
 32             lower_bound (vec[v].begin(), vec[v].end(), node(u)) -> del = true;
 33         }
 34     }
 35 } query[N];
 36 
 37 int n, m, q;
 38 
 39 void init ()
 40 {
 41     for (int i=0; i<=n; i++)
 42         vec[i].clear();
 43 }
 44 
 45 struct bit_tree
 46 {
 47     int tree[maxn];
 48     
 49     void init()
 50     {
 51         memset (tree, 0, sizeof(tree));
 52     }
 53     
 54     int lowbit (int x)
 55     {
 56         return x & (-x);
 57     }
 58     
 59     void change (int x, int num)
 60     {
 61         while (x <= n)
 62         {
 63             tree[x] += num;
 64             x += lowbit (x);
 65         }
 66     }
 67     
 68     void update (int x, int y, int num)
 69     {
 70         change (x, num);
 71         change (y+1, -num);
 72     }
 73     
 74     int query (int x)
 75     {
 76         int res = 0;
 77         while (x)
 78         {
 79             res += tree[x];
 80             x -= lowbit (x);
 81         }
 82         return res;
 83     }
 84     
 85 }Bit_tree;
 86 
 87 int begin_id[maxn], end_id[maxn], deep[maxn], ntime;
 88 int fa[maxn][M];
 89 void dfs (int u, int father, int dep)
 90 {
 91     if (father > 0)
 92         vec[u].erase (lower_bound(vec[u].begin(), vec[u].end(), node(father)));
 93         
 94     fa[u][0] = father;
 95     begin_id[u] = ++ntime;
 96     deep[u] = dep;
 97     
 98     for (int i=0; i<vec[u].size(); i++)
 99     {
100         node p = vec[u][i];
101         if (p.del || begin_id[p.to]) continue;
102         vec[u][i].del = true;
103         dfs (p.to, u, dep+1);
104     }
105     
106     end_id[u] = ntime;
107     Bit_tree.update (begin_id[u], end_id[u], 1);
108 }
109 
110 struct Lca
111 {
112     void init ()
113     {
114         for (int i=1; i<M; i++)
115             for (int j=1; j<=n; j++)
116                 fa[j][i] = fa[fa[j][i-1]][i-1];
117     }
118     
119     int lca (int u, int v)
120     {
121         if (deep[u] < deep[v])   swap (u, v);
122         int num = deep[u] - deep[v];
123         for (int i=0; i<M; i++)
124             if ((1<<i) & num)   u = fa[u][i];
125         if (u == v) return u;
126         for (int i=M-1; i>=0; i--)
127             if (fa[u][i] != fa[v][i])
128             {
129                 u = fa[u][i];
130                 v = fa[v][i];
131             }
132         return fa[u][0];
133     }
134     
135 }LCA;
136 
137 int father[maxn];
138 struct UNion
139 {
140     void init()
141     {
142         for (int i=0; i<=n; i++)
143             father[i] = i;
144     }
145     
146     int find (int x)
147     {
148         if (x != father[x]) father[x] = find (father[x]);
149         return father[x];
150     }
151     
152     void merge_fa (int x, int y)
153     {
154         x = find (x);
155         while (x != y)
156         {
157             int t = find(fa[x][0]);
158             father[x] = t;
159             Bit_tree.update(begin_id[x], end_id[x], -1);
160             x = t;
161         }
162     }
163     
164     void merge (int x, int y)
165     {
166         int l = find (LCA.lca (x, y));
167         merge_fa (x, l);
168         merge_fa (y, l);
169     }
170     
171 }Union;
172 
173 int ans[N], res;
174 void solve ()
175 {
176     Bit_tree.init ();
177     ntime = res = 0;
178     memset (begin_id, 0, sizeof(begin_id));
179     dfs (1, 0, 1);
180     LCA.init ();
181     Union.init();
182     
183     for (int i=1; i<=n; i++)
184     {
185         for (int j=0; j<vec[i].size(); j++)
186         {
187             node p = vec[i][j];
188             if (p.del)  continue;
189             Union.merge (p.to, i);
190         }
191     }
192 
193     for (int i=q; i>0; i--)
194     {
195         Query p = query[i];
196         int u = begin_id[p.u];
197         int v = begin_id[p.v];
198         int x = begin_id[LCA.lca(p.u, p.v)];
199         if (p.op == 1)
200             Union.merge(p.u, p.v);
201         else
202             ans[++ res] = Bit_tree.query(u) + Bit_tree.query(v) - 2*Bit_tree.query(x);
203     }
204     
205     while(res)
206         printf ("%d
", ans[res --]);
207 }
208 
209 int main ()
210 {
211     int t, u, v;
212     scanf ("%d", &t);
213     
214     for (int i=1; i<=t; i++)
215     {
216         scanf("%d %d %d", &n, &m, &q);
217         init ();
218         
219         for (int j=0; j<m; j++)
220         {
221             scanf ("%d %d", &u, &v);
222             vec[u].push_back (node(v));
223             vec[v].push_back (node(u));
224         }
225         
226         for (int j=1; j<=n; j++)
227             sort (vec[j].begin(), vec[j].end());
228             
229         for (int j=1; j<=q; j++)
230             query[j].read();
231             
232         printf ("Case #%d:
", i);
233         solve ();
234         
235     }
236     return 0;
237 }

  

本文为博主原创文章,未经博主允许不得转载。
原文地址:https://www.cnblogs.com/alihenaixiao/p/4845733.html