HDU 5458 Stability(LCA倍增算法, 并查集缩点(一般都是连通缩点))
来源:互联网 发布:Windows匿名用户 编辑:程序博客网 时间:2024/06/14 15:32
转载地址:http://www.cnblogs.com/oyking/p/4821902.html
题目大意:给一个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))
#include <cstdio>#include <algorithm>#include <iostream>#include <cstring>#include <vector>#include <cctype>using namespace std;typedef long long LL;const int MAXV = 30010;const int MAXQ = 100010;const int MAX_LOG = 16;const int INF = 0x3f3f3f3f;const int MOD = 1e9 + 7;int readint() { char c = getchar(); while(!isdigit(c)) c = getchar(); int res = 0; while(isdigit(c)) res = res * 10 + c - '0', c = getchar(); return res;}struct Node { int to, del; Node(int to): to(to), del(0) {} bool operator < (const Node &rhs) const { if(to != rhs.to) return to < rhs.to; return del > rhs.del; }};vector<Node> adjs[MAXV];int n, m, q, T;void init() { for(int i = 1; i <= n; ++i) { adjs[i].clear(); }}void add_edge(int u, int v) { adjs[u].push_back(Node(v)); adjs[v].push_back(Node(u));}struct Query { int op, a, b, apos, bpos; void read() { scanf("%d%d%d", &op, &a, &b); if(op == 1) { lower_bound(adjs[a].begin(), adjs[a].end(), Node(b))->del = true; lower_bound(adjs[b].begin(), adjs[b].end(), Node(a))->del = true; } }} query[MAXQ];int ans[MAXQ], acnt;struct BIT { int tree[MAXV]; void init() { memset(tree + 1, 0, n * sizeof(int)); } int lowbit(int x) { return x & -x; } void modify(int x, int val) { while(x <= n) { tree[x] += val; x += lowbit(x); } } void modify(int a, int b, int val) { modify(a, val); modify(b + 1, -val); } int get_val(int x) { int res = 0; while(x) { res += tree[x]; x -= lowbit(x); } return res; }} bitree;int bid[MAXV], eid[MAXV], dep[MAXV];int fa[MAX_LOG][MAXV];int dfs_clock;void dfs_id(int u, int f, int depth) { if(f > 0) adjs[u].erase(lower_bound(adjs[u].begin(), adjs[u].end(), Node(f))); fa[0][u] = f; dep[u] = depth; bid[u] = ++dfs_clock; for(Node& p : adjs[u]) if(!p.del && !bid[p.to]) { p.del = 1; dfs_id(p.to, u, depth + 1); } eid[u] = dfs_clock; bitree.modify(bid[u], eid[u], 1);}void bit_init() { memset(bid + 1, 0, n * sizeof(int)); bitree.init(); dfs_clock = 0; dfs_id(1, 0, 0);}struct LCA { void init_lca() { for(int k = 0; k + 1 < MAX_LOG; ++k) { for(int u = 1; u <= n; ++u) { if(fa[k][u] == -1) fa[k + 1][u] = -1; else fa[k + 1][u] = fa[k][fa[k][u]]; } } } int ask(int u, int v) { if(dep[u] < dep[v]) swap(u, v); for(int k = 0; k < MAX_LOG; ++k) { if((dep[u] - dep[v]) & (1 << k)) u = fa[k][u]; } if(u == v) return u; for(int k = MAX_LOG - 1; k >= 0; --k) { if(fa[k][u] != fa[k][v]) u = fa[k][u], v = fa[k][v]; } return fa[0][u]; }} lca;int dsu[MAXV];int find_set(int x) { return dsu[x] == x ? x : dsu[x] = find_set(dsu[x]);}void mergeFa(int u, int gold) { u = find_set(u); while(u != gold) { int t = find_set(fa[0][u]); dsu[u] = t; bitree.modify(bid[u], eid[u], -1); u = t; }}void merge(int u, int v) { int l = find_set(lca.ask(u, v)); mergeFa(u, l); mergeFa(v, l);}void init_tree() { for(int i = 1; i <= n; ++i) dsu[i] = i; for(int u = 1; u <= n; ++u) for(Node p : adjs[u]) if(!p.del) { merge(u, p.to); }}void solve() { bit_init(); lca.init_lca(); init_tree(); for(int i = q - 1; i >= 0; --i) { if(query[i].op == 1) { merge(query[i].a, query[i].b); } else { int l = lca.ask(query[i].a, query[i].b); ans[acnt++] = bitree.get_val(bid[query[i].a]) + bitree.get_val(bid[query[i].b]) - 2 * bitree.get_val(bid[l]); } } for(int i = acnt - 1; i >= 0; --i) printf("%d\n", ans[i]);}int main() { scanf("%d", &T); for(int t = 1; t <= T; ++t) { scanf("%d%d%d", &n, &m, &q); init(); for(int i = 0, u, v; i < m; ++i) { u = readint(), v = readint(); add_edge(u, v); } for(int i = 1; i <= n; ++i) sort(adjs[i].begin(), adjs[i].end()); acnt = 0; for(int i = 0; i < q; ++i) query[i].read(); printf("Case #%d:\n", t); solve(); }}
- HDU 5458 Stability(LCA倍增算法, 并查集缩点(一般都是连通缩点))
- hdu 5458 Stability(树链剖分+强连通缩点+线段树)
- hdu 5934(强连通缩点)
- hdu 4674 边双连通缩点+倍增lca+麻烦的讨论 (2013多校联合)
- hdu 4674 (缩点 + 倍增LCA)
- hdu 4635 Strongly connected (强连通缩点)
- HDU 5934 Bomb(强连通缩点)
- HDU 6165 FFF at Valentine(强连通缩点)
- HDU 5934-Bomb(强连通缩点)
- hdu 2767 强连通缩点
- hdu 1827 强连通缩点
- HDU 3639 强连通缩点优化
- hdu 3072 (强连通缩点)
- hdu 3639 (强连通缩点+搜索)
- hdu 4635 (强连通缩点)
- HDU 1827 强连通缩点
- hdu 4635 强连通缩点
- HDU 2767 强连通缩点
- C++多线程定时器完整实现
- java常用设计模式
- 利用余弦定理制作连杆效果
- TT内存清理
- A possible solution of MySQL workbench cannot connect to local host error on MAC
- HDU 5458 Stability(LCA倍增算法, 并查集缩点(一般都是连通缩点))
- 在MyEClipse中的console显示sql语句
- 魔术师发牌
- 四月巴厘岛家庭游 - 2015
- Linux下svn不能连接上Windows服务器
- 【springmvc+mybatis项目实战】杰信商贸-23.重点知识回顾
- U3D Animator 中的正播倒播
- 关于Debug和Release之本质区别的讨论
- 笔记--语音信号的预加重