洛谷P3300 城市规划
题意:给你一个6 * n的网格题,单点修改,询问区间联通块数。n <= 10w
解:看起来就很显然的一道题......线段树每个点用一个ufs维护连通性。完了。
我为了方便思考把图转成横着的了。
写起来真是毒瘤......
重点在于:1.建立叶节点。2.合并两个子节点。3.把新的并查集的中间两列压掉。
第一步,这个就直接枚举,merge就完事了。
第二步,把两个2列的子并查集copy到当前节点的4列的并查集上。注意右边那个并查集,fa全部要加2m,因为下标加了2m。
然后枚举中间两列merge。这样也做完了。
第三步,我们只要保留两边的两列即可。注意到有可能有两边元素的代表元在中间,我们使用左偏树技巧,切换代表元到它自己,注意vis也要变。
然后把两边的vis和facopy一份出来,用以查询代表元。
然后把前两列init,然后枚举每个元素,跟它的代表元merge。注意这一步会对连通块总数tot造成改变,最后复原即可。
最后把前两列的vis和lk从copy的那里拿来用即可。
注意,vis(当前联通块是否有建筑物)要继承代表元的,lk(能否与两边连通)直接从对应下标继承,这两个不一样!
具体实现看代码吧......
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 #define ck(x) ((x) == '+' || (x) == '|') 4 5 const int N = 100010; 6 7 template <typename T> inline void read(T &x) { 8 x = 0; 9 char c = getchar(); 10 while(c < '0' || c > '9') { 11 c = getchar(); 12 } 13 while(c >= '0' && c <= '9') { 14 x = x * 10 + c - 48; 15 c = getchar(); 16 } 17 return; 18 } 19 20 int n, m, gt[24], GT, exfa[24], exvis[24], exlk[24], newvis[24], newlk[24]; 21 22 int exfind(int x) { 23 return (x == exfa[x]) ? x : exfa[x] = exfind(exfa[x]); 24 } 25 26 inline int trans(int x) { 27 return x < m ? x : x - (m << 1); 28 } 29 30 struct Node { 31 int fa[24], tot; 32 std::bitset<24> lk, vis; 33 int find(int x) { 34 return (x == fa[x]) ? x : (fa[x] = find(fa[x])); 35 } 36 inline void Merge(int x, int y) { 37 x = find(x); 38 y = find(y); 39 if(x == y) return; 40 fa[y] = x; 41 tot -= (vis[x] && vis[y]); 42 if(vis[y]) vis.set(x); 43 return; 44 } 45 Node() {} 46 Node(char *a) { 47 tot = 0; 48 for(register int i(0); i < m; ++i) { 49 fa[i + m] = fa[i] = i; 50 if(a[i] == 'O') { 51 vis.set(i); 52 vis.set(i + m); 53 lk.set(i); 54 lk.set(i + m); 55 ++tot; 56 } 57 else if(a[i] == '.') { 58 vis.reset(i); 59 vis.reset(i + m); 60 lk.reset(i); 61 lk.reset(i + m); 62 } 63 else if(a[i] == '-' || a[i] == '+') { 64 vis.reset(i); 65 vis.reset(i + m); 66 lk.set(i); 67 lk.set(i + m); 68 } 69 } 70 for(register int i(1); i < m; ++i) { 71 if(ck(a[i - 1]) && ck(a[i])) { 72 Merge(i - 1, i); 73 } 74 else if((ck(a[i - 1]) && a[i] == 'O') || (ck(a[i]) && a[i - 1] == 'O')) { 75 Merge(i - 1, i); 76 } 77 else if(a[i] == 'O' && a[i - 1] == 'O') { 78 Merge(i - 1, i); 79 } 80 } 81 } 82 inline void update() { 83 for(register int i(0); i < m; ++i) { 84 int t(find(i)); 85 fa[i] = fa[t] = i; 86 vis[i] = vis[t]; 87 88 t = find(i + m * 3); 89 fa[i + m * 3] = fa[t] = i + m * 3; 90 vis[i + m * 3] = vis[t]; 91 } 92 93 memcpy(exfa, fa, sizeof(fa)); 94 for(register int i(0); i < m; ++i) { 95 exvis[i] = vis[i]; 96 exvis[i + m * 3] = vis[i + m * 3]; 97 exlk[i] = lk[i]; 98 exlk[i + m * 3] = lk[i + m * 3]; 99 } 100 101 int temp = tot; 102 for(register int i(0); i < m; ++i) { 103 fa[i] = i; 104 fa[i + m] = i + m; 105 } 106 for(register int i(0); i < m; ++i) { 107 Merge(i, trans(exfind(i))); 108 Merge(i + m, trans(exfind(i + m * 3))); 109 } 110 for(register int i(0); i < m; ++i) { 111 vis[i] = exvis[exfind(i)]; 112 vis[i + m] = exvis[exfind(i + m * 3)]; 113 lk[i] = exlk[i]; 114 lk[i + m] = exlk[i + m * 3]; 115 } 116 tot = temp; 117 return; 118 } 119 inline Node merge(const Node &w) const { 120 Node ans; 121 /// copy 122 for(register int i(0); i < m; ++i) { 123 ans.fa[i] = fa[i]; 124 ans.lk[i] = lk[i]; 125 ans.vis[i] = vis[i]; 126 127 ans.fa[i + m] = fa[i + m]; 128 ans.lk[i + m] = lk[i + m]; 129 ans.vis[i + m] = vis[i + m]; 130 131 ans.fa[i + m * 2] = w.fa[i] + m * 2; 132 ans.lk[i + m * 2] = w.lk[i]; 133 ans.vis[i + m * 2] = w.vis[i]; 134 135 ans.fa[i + m * 3] = w.fa[i + m] + m * 2; 136 ans.lk[i + m * 3] = w.lk[i + m]; 137 ans.vis[i + m * 3] = w.vis[i + m]; 138 } 139 ans.tot = tot + w.tot; 140 /// merge 141 for(register int i(0); i < m; ++i) { 142 if(ans.lk[i + m] && ans.lk[i + m * 2]) { /// -> <- 143 ans.Merge(i + m, i + m * 2); 144 } 145 } 146 ans.update(); 147 return ans; 148 } 149 }node[N << 2]; 150 151 char str[N][6]; 152 153 void build(int l, int r, int o) { 154 if(l == r) { 155 node[o] = Node(str[r]); 156 return; 157 } 158 int mid = (l + r) >> 1; 159 build(l, mid, o << 1); 160 build(mid + 1, r, o << 1 | 1); 161 node[o] = node[o << 1].merge(node[o << 1 | 1]); 162 return; 163 } 164 165 void change(int p, int l, int r, int o) { 166 if(l == r) { 167 node[o] = Node(str[r]); 168 return; 169 } 170 int mid = (l + r) >> 1; 171 if(p <= mid) { 172 change(p, l, mid, o << 1); 173 } 174 else { 175 change(p, mid + 1, r, o << 1 | 1); 176 } 177 node[o] = node[o << 1].merge(node[o << 1 | 1]); 178 return; 179 } 180 181 Node ask(int L, int R, int l, int r, int o) { 182 if(L <= l && r <= R) { 183 return node[o]; 184 } 185 int mid = (l + r) >> 1; 186 if(R <= mid) { 187 return ask(L, R, l, mid, o << 1); 188 } 189 if(mid < L) { 190 return ask(L, R, mid + 1, r, o << 1 | 1); 191 } 192 Node temp(ask(L, R, l, mid, o << 1)); 193 temp = temp.merge(ask(L, R, mid + 1, r, o << 1 | 1)); 194 return temp; 195 } 196 197 int main() { 198 199 read(n); read(m); 200 for(int i = 1; i <= n; i++) { 201 scanf("%s", str[i]); 202 for(int j = 0; j < m; j++) { 203 if(str[i][j] == '-') { 204 str[i][j] = '|'; 205 } 206 else if(str[i][j] == '|') { 207 str[i][j] = '-'; 208 } 209 } 210 } 211 212 build(1, n, 1); 213 214 int q, x, y; 215 char ss[2]; 216 read(q); 217 for(int i = 1; i <= q; i++) { 218 scanf("%s", ss); read(x); read(y); 219 if(ss[0] == 'C') { /// change 220 scanf("%s", ss); 221 if(ss[0] == '-') { 222 ss[0] = '|'; 223 } 224 else if(ss[0] == '|') { 225 ss[0] = '-'; 226 } 227 str[x][y - 1] = ss[0]; 228 change(x, 1, n, 1); 229 } 230 else { /// Query 231 Node temp = ask(x, y, 1, n, 1); 232 printf("%d\n", temp.tot); 233 } 234 } 235 236 return 0; 237 }
这代码常数奇大...