题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458
Then for each query, print one line containing the stability between corresponding pair of nodes.
题目大意:给一个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; 26 Node(int to): to(to), del(0) {} 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)); 43 adjs[v].push_back(Node(u)); 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 lower_bound(adjs[a].begin(), adjs[a].end(), Node(b))->del = true; 52 lower_bound(adjs[b].begin(), adjs[b].end(), Node(a))->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], dep[MAXV]; 87 int fa[MAX_LOG][MAXV]; 88 int dfs_clock; 89 90 void dfs_id(int u, int f, int depth) { 91 if(f > 0) adjs[u].erase(lower_bound(adjs[u].begin(), adjs[u].end(), Node(f))); 92 fa[0][u] = f; 93 dep[u] = depth; 94 bid[u] = ++dfs_clock; 95 for(Node& p : adjs[u]) if(!p.del && !bid[p.to]) { 96 p.del = 1; 97 dfs_id(p.to, u, depth + 1); 98 } 99 eid[u] = dfs_clock; 100 bitree.modify(bid[u], eid[u], 1); 101 } 102 void bit_init() { 103 memset(bid + 1, 0, n * sizeof(int)); 104 bitree.init(); 105 dfs_clock = 0; 106 dfs_id(1, 0, 0); 107 } 108 109 struct LCA { 110 void init_lca() { 111 for(int k = 0; k + 1 < MAX_LOG; ++k) { 112 for(int u = 1; u <= n; ++u) { 113 if(fa[k][u] == -1) fa[k + 1][u] = -1; 114 else fa[k + 1][u] = fa[k][fa[k][u]]; 115 } 116 } 117 } 118 119 int ask(int u, int v) { 120 if(dep[u] < dep[v]) swap(u, v); 121 for(int k = 0; k < MAX_LOG; ++k) { 122 if((dep[u] - dep[v]) & (1 << k)) u = fa[k][u]; 123 } 124 if(u == v) return u; 125 for(int k = MAX_LOG - 1; k >= 0; --k) { 126 if(fa[k][u] != fa[k][v]) 127 u = fa[k][u], v = fa[k][v]; 128 } 129 return fa[0][u]; 130 } 131 } lca; 132 133 int dsu[MAXV]; 134 135 int find_set(int x) { 136 return dsu[x] == x ? x : dsu[x] = find_set(dsu[x]); 137 } 138 139 void mergeFa(int u, int gold) { 140 u = find_set(u); 141 while(u != gold) { 142 int t = find_set(fa[0][u]); 143 dsu[u] = t; 144 bitree.modify(bid[u], eid[u], -1); 145 u = t; 146 } 147 } 148 149 void merge(int u, int v) { 150 int l = find_set(lca.ask(u, v)); 151 mergeFa(u, l); 152 mergeFa(v, l); 153 } 154 155 void init_tree() { 156 for(int i = 1; i <= n; ++i) 157 dsu[i] = i; 158 for(int u = 1; u <= n; ++u) 159 for(Node p : adjs[u]) if(!p.del) { 160 merge(u, p.to); 161 } 162 } 163 164 void solve() { 165 bit_init(); 166 lca.init_lca(); 167 init_tree(); 168 for(int i = q - 1; i >= 0; --i) { 169 if(query[i].op == 1) { 170 merge(query[i].a, query[i].b); 171 } else { 172 int l = lca.ask(query[i].a, query[i].b); 173 ans[acnt++] = bitree.get_val(bid[query[i].a]) + bitree.get_val(bid[query[i].b]) - 2 * bitree.get_val(bid[l]); 174 } 175 } 176 for(int i = acnt - 1; i >= 0; --i) 177 printf("%d\n", ans[i]); 178 } 179 180 int main() { 181 scanf("%d", &T); 182 for(int t = 1; t <= T; ++t) { 183 scanf("%d%d%d", &n, &m, &q); 184 init(); 185 for(int i = 0, u, v; i < m; ++i) { 186 u = readint(), v = readint(); 187 add_edge(u, v); 188 } 189 for(int i = 1; i <= n; ++i) 190 sort(adjs[i].begin(), adjs[i].end()); 191 192 acnt = 0; 193 for(int i = 0; i < q; ++i) 194 query[i].read(); 195 196 printf("Case #%d:\n", t); 197 solve(); 198 } 199 }