题目大意:给一个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 }