洛谷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(能否与两边连通)直接从对应下标继承,这两个不一样!

具体实现看代码吧......

  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 }
AC代码

这代码常数奇大...

 

转载于:https://www.cnblogs.com/huyufeifei/p/10841280.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值