码迷,mamicode.com
首页 > 编程语言 > 详细

HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

时间:2015-09-19 19:36:14      阅读:741      评论:0      收藏:0      [点我收藏+]

标签:

 

题目大意:给一个N个点M条边的无向图,有Q个询问:1、删掉a、b之间所存在的边;2、询问有多少条边,单独删掉之后a与b不再连通。

思路:脑洞大开。

对于询问,首先想到的就是a与b之间有多少桥(割边),然后想到双连通分量,然而删边是个坑爹的问题,于是我们离线倒着来,把删边变成加边。

双连通分量这种东西呢,其实缩点连起来之后,就是一棵树辣。

然后询问两个点的时候,设根到点x的距离为dep[x],a、b的最近公共祖先为lca(a, b),那么询问query(a, b) = dep[a] + dep[b] - 2 * dep[lca(a, b)]

加一条边的时候呢,比如加edge(a, b),那么原来的a到b的路径就形成了一个环,那么这个环就应该缩成一个双连通分量(每个点只会被缩一次,平摊的复杂度肯定是没问题的)。

这里可以用并查集来维护同一个双连通分量,每次都是儿子合并到父亲,然后每一次点u合并到父亲的时候,u和u的所有子孙的高度都会减一。

因为要处理一棵子树的所有值,这里使用DFS序+树状数组的方法来维护每个点的深度dep。

然后求LCA这里用的是树上倍增。整个题目要做的就是这些了。

 

然后整个流程就是:

1、初始化边表并读入所有数据并给边表排序用于查找(我这里用了vector)。(复杂度O(n+m+q+mlog(m)))

2、然后给1操作涉及的边打个删除标记。(复杂度O(qlog(m)))

3、DFS随便建一棵树,给DFS到的边打个删除标记(我直接把父边从vector移除了),顺便建立好DFS序和树状数组、dep和fa数组(用于LCA倍增)。(复杂度O(n+m+nlog(n)))

4、初始化LCA倍增。(复杂度O(nlog(n)))

5、对于每条没打标记的边(即树里的横向边?) edge(a, b),合并路径path(a, b)上的所有点,并维护好树状数组。(复杂度为O(m+nlog(n)))

6、逆序跑询问,第一个操作就加边,加边方法同流程4,第二个操作便是求出LCA,然后用树状数组扒出每个点的深度,然后加加减减得到结果并存起来。(复杂度O(qlog(n)+nlog(n))))

7、输出结果。(复杂度O(q))

 

代码(889MS):

技术分享
  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <vector>
  6 #include <cctype>
  7 using namespace std;
  8 typedef long long LL;
  9 
 10 const int MAXV = 30010;
 11 const int MAXQ = 100010;
 12 const int MAX_LOG = 16;
 13 const int INF = 0x3f3f3f3f;
 14 const int MOD = 1e9 + 7;
 15 
 16 int readint() {
 17     char c = getchar();
 18     while(!isdigit(c)) c = getchar();
 19     int res = 0;
 20     while(isdigit(c)) res = res * 10 + c - 0, c = getchar();
 21     return res;
 22 }
 23 
 24 struct Node {
 25     int to, del, f;
 26     Node(int to, int f = 0): to(to), del(0), f(f) {}
 27     bool operator < (const Node &rhs) const {
 28         if(to != rhs.to) return to < rhs.to;
 29         return del > rhs.del;
 30     }
 31 };
 32 vector<Node> adjs[MAXV];
 33 int n, m, q, T;
 34 
 35 void init() {
 36     for(int i = 1; i <= n; ++i) {
 37         adjs[i].clear();
 38     }
 39 }
 40 
 41 void add_edge(int u, int v) {
 42     adjs[u].push_back(Node(v, adjs[v].size()));
 43     adjs[v].push_back(Node(u, adjs[u].size() - 1));
 44 }
 45 
 46 struct Query {
 47     int op, a, b, apos, bpos;
 48     void read() {
 49         scanf("%d%d%d", &op, &a, &b);
 50         if(op == 1) {
 51             auto it = lower_bound(adjs[a].begin(), adjs[a].end(), Node(b));
 52             it->del = adjs[b][it->f].del = true;
 53         }
 54     }
 55 } query[MAXQ];
 56 int ans[MAXQ], acnt;
 57 
 58 struct BIT {
 59     int tree[MAXV];
 60     void init() {
 61         memset(tree + 1, 0, n * sizeof(int));
 62     }
 63     int lowbit(int x) {
 64         return x & -x;
 65     }
 66     void modify(int x, int val) {
 67         while(x <= n) {
 68             tree[x] += val;
 69             x += lowbit(x);
 70         }
 71     }
 72     void modify(int a, int b, int val) {
 73         modify(a, val);
 74         modify(b + 1, -val);
 75     }
 76     int get_val(int x) {
 77         int res = 0;
 78         while(x) {
 79             res += tree[x];
 80             x -= lowbit(x);
 81         }
 82         return res;
 83     }
 84 } bitree;
 85 
 86 int bid[MAXV], eid[MAXV];
 87 int dfs_clock;
 88 
 89 void dfs_id(int u) {
 90     bid[u] = ++dfs_clock;
 91     for(Node& p : adjs[u]) if(!p.del && !bid[p.to]) {
 92         p.del = adjs[p.to][p.f].del = 2;
 93         dfs_id(p.to);
 94     }
 95     eid[u] = dfs_clock;
 96     bitree.modify(bid[u], eid[u], 1);
 97 }
 98 void bit_init() {
 99     memset(bid + 1, 0, n * sizeof(int));
100     bitree.init();
101     dfs_id(1);
102 }
103 
104 struct LCA {
105     int fa[MAX_LOG][MAXV];
106     int dep[MAXV];
107 
108     void dfs_lca(int u, int f, int depth) {
109         dep[u] = depth;
110         fa[0][u] = f;
111         for(Node p : adjs[u]) if(p.del == 2 && p.to != f)
112             dfs_lca(p.to, u, depth + 1);
113     }
114 
115     void init_lca() {
116         dfs_lca(1, -1, 0);
117         for(int k = 0; k + 1 < MAX_LOG; ++k) {
118             for(int u = 1; u <= n; ++u) {
119                 if(fa[k][u] == -1) fa[k + 1][u] = -1;
120                 else fa[k + 1][u] = fa[k][fa[k][u]];
121             }
122         }
123     }
124 
125     int ask(int u, int v) {
126         if(dep[u] < dep[v]) swap(u, v);
127         for(int k = 0; k < MAX_LOG; ++k) {
128             if((dep[u] - dep[v]) & (1 << k)) u = fa[k][u];
129         }
130         if(u == v) return u;
131         for(int k = MAX_LOG - 1; k >= 0; --k) {
132             if(fa[k][u] != fa[k][v])
133                 u = fa[k][u], v = fa[k][v];
134         }
135         return fa[0][u];
136     }
137 } lca;
138 
139 int dsu[MAXV];
140 
141 int find_set(int x) {
142     return dsu[x] == x ? x : dsu[x] = find_set(dsu[x]);
143 }
144 
145 void mergeFa(int u, int gold) {
146     u = find_set(u);
147     while(u != gold) {
148         int t = find_set(lca.fa[0][u]);
149         dsu[u] = t;
150         bitree.modify(bid[u], eid[u], -1);
151         u = t;
152     }
153 }
154 
155 void merge(int u, int v) {
156     int l = find_set(lca.ask(u, v));
157     mergeFa(u, l);
158     mergeFa(v, l);
159 }
160 
161 void init_tree() {
162     for(int i = 1; i <= n; ++i)
163         dsu[i] = i;
164     for(int u = 1; u <= n; ++u)
165         for(Node p : adjs[u]) if(!p.del) {
166             merge(u, p.to);
167             p.del = adjs[p.to][p.f].del = 2;
168         }
169 }
170 
171 void solve() {
172     bit_init();
173     lca.init_lca();
174     init_tree();
175     for(int i = q - 1; i >= 0; --i) {
176         if(query[i].op == 1) {
177             merge(query[i].a, query[i].b);
178         } else {
179             int l = lca.ask(query[i].a, query[i].b);
180             ans[acnt++] = bitree.get_val(bid[query[i].a]) + bitree.get_val(bid[query[i].b]) - 2 * bitree.get_val(bid[l]);
181         }
182     }
183     for(int i = acnt - 1; i >= 0; --i)
184         printf("%d\n", ans[i]);
185 }
186 
187 int main() {
188     scanf("%d", &T);
189     for(int t = 1; t <= T; ++t) {
190         scanf("%d%d%d", &n, &m, &q);
191         init();
192         for(int i = 0, u, v; i < m; ++i) {
193             u = readint(), v = readint();
194             add_edge(u, v);
195         }
196         for(int i = 1; i <= n; ++i)
197             sort(adjs[i].begin(), adjs[i].end());
198 
199         acnt = 0;
200         for(int i = 0; i < q; ++i)
201             query[i].read();
202 
203         printf("Case #%d:\n", t);
204         solve();
205     }
206 }
View Code

 

HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

标签:

原文地址:http://www.cnblogs.com/oyking/p/4821902.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!