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

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

 #include <bits/stdc++.h>

 #define ck(x) ((x) == '+' || (x) == '|')

 const int N = ;

 template <typename T> inline void read(T &x) {
x = ;
char c = getchar();
while(c < '' || c > '') {
c = getchar();
}
while(c >= '' && c <= '') {
x = x * + c - ;
c = getchar();
}
return;
} int n, m, gt[], GT, exfa[], exvis[], exlk[], newvis[], newlk[]; int exfind(int x) {
return (x == exfa[x]) ? x : exfa[x] = exfind(exfa[x]);
} inline int trans(int x) {
return x < m ? x : x - (m << );
} struct Node {
int fa[], tot;
std::bitset<> lk, vis;
int find(int x) {
return (x == fa[x]) ? x : (fa[x] = find(fa[x]));
}
inline void Merge(int x, int y) {
x = find(x);
y = find(y);
if(x == y) return;
fa[y] = x;
tot -= (vis[x] && vis[y]);
if(vis[y]) vis.set(x);
return;
}
Node() {}
Node(char *a) {
tot = ;
for(register int i(); i < m; ++i) {
fa[i + m] = fa[i] = i;
if(a[i] == 'O') {
vis.set(i);
vis.set(i + m);
lk.set(i);
lk.set(i + m);
++tot;
}
else if(a[i] == '.') {
vis.reset(i);
vis.reset(i + m);
lk.reset(i);
lk.reset(i + m);
}
else if(a[i] == '-' || a[i] == '+') {
vis.reset(i);
vis.reset(i + m);
lk.set(i);
lk.set(i + m);
}
}
for(register int i(); i < m; ++i) {
if(ck(a[i - ]) && ck(a[i])) {
Merge(i - , i);
}
else if((ck(a[i - ]) && a[i] == 'O') || (ck(a[i]) && a[i - ] == 'O')) {
Merge(i - , i);
}
else if(a[i] == 'O' && a[i - ] == 'O') {
Merge(i - , i);
}
}
}
inline void update() {
for(register int i(); i < m; ++i) {
int t(find(i));
fa[i] = fa[t] = i;
vis[i] = vis[t]; t = find(i + m * );
fa[i + m * ] = fa[t] = i + m * ;
vis[i + m * ] = vis[t];
} memcpy(exfa, fa, sizeof(fa));
for(register int i(); i < m; ++i) {
exvis[i] = vis[i];
exvis[i + m * ] = vis[i + m * ];
exlk[i] = lk[i];
exlk[i + m * ] = lk[i + m * ];
} int temp = tot;
for(register int i(); i < m; ++i) {
fa[i] = i;
fa[i + m] = i + m;
}
for(register int i(); i < m; ++i) {
Merge(i, trans(exfind(i)));
Merge(i + m, trans(exfind(i + m * )));
}
for(register int i(); i < m; ++i) {
vis[i] = exvis[exfind(i)];
vis[i + m] = exvis[exfind(i + m * )];
lk[i] = exlk[i];
lk[i + m] = exlk[i + m * ];
}
tot = temp;
return;
}
inline Node merge(const Node &w) const {
Node ans;
/// copy
for(register int i(); i < m; ++i) {
ans.fa[i] = fa[i];
ans.lk[i] = lk[i];
ans.vis[i] = vis[i]; ans.fa[i + m] = fa[i + m];
ans.lk[i + m] = lk[i + m];
ans.vis[i + m] = vis[i + m]; ans.fa[i + m * ] = w.fa[i] + m * ;
ans.lk[i + m * ] = w.lk[i];
ans.vis[i + m * ] = w.vis[i]; ans.fa[i + m * ] = w.fa[i + m] + m * ;
ans.lk[i + m * ] = w.lk[i + m];
ans.vis[i + m * ] = w.vis[i + m];
}
ans.tot = tot + w.tot;
/// merge
for(register int i(); i < m; ++i) {
if(ans.lk[i + m] && ans.lk[i + m * ]) { /// -> <-
ans.Merge(i + m, i + m * 2);
}
}
ans.update();
return ans;
}
}node[N << ]; char str[N][]; void build(int l, int r, int o) {
if(l == r) {
node[o] = Node(str[r]);
return;
}
int mid = (l + r) >> ;
build(l, mid, o << );
build(mid + , r, o << | );
node[o] = node[o << ].merge(node[o << | ]);
return;
} void change(int p, int l, int r, int o) {
if(l == r) {
node[o] = Node(str[r]);
return;
}
int mid = (l + r) >> ;
if(p <= mid) {
change(p, l, mid, o << );
}
else {
change(p, mid + , r, o << | );
}
node[o] = node[o << ].merge(node[o << | ]);
return;
} Node ask(int L, int R, int l, int r, int o) {
if(L <= l && r <= R) {
return node[o];
}
int mid = (l + r) >> ;
if(R <= mid) {
return ask(L, R, l, mid, o << );
}
if(mid < L) {
return ask(L, R, mid + , r, o << | );
}
Node temp(ask(L, R, l, mid, o << ));
temp = temp.merge(ask(L, R, mid + , r, o << | ));
return temp;
} int main() { read(n); read(m);
for(int i = ; i <= n; i++) {
scanf("%s", str[i]);
for(int j = ; j < m; j++) {
if(str[i][j] == '-') {
str[i][j] = '|';
}
else if(str[i][j] == '|') {
str[i][j] = '-';
}
}
} build(, n, ); int q, x, y;
char ss[];
read(q);
for(int i = ; i <= q; i++) {
scanf("%s", ss); read(x); read(y);
if(ss[] == 'C') { /// change
scanf("%s", ss);
if(ss[] == '-') {
ss[] = '|';
}
else if(ss[] == '|') {
ss[] = '-';
}
str[x][y - ] = ss[];
change(x, , n, );
}
else { /// Query
Node temp = ask(x, y, , n, );
printf("%d\n", temp.tot);
}
} return ;
}

AC代码

这代码常数奇大...

洛谷P3300 城市规划的更多相关文章

  1. 洛谷 P4841 城市规划 解题报告

    P4841 城市规划 题意 n个有标号点的简单(无重边无自环)无向连通图数目. 输入输出格式 输入格式: 仅一行一个整数\(n(\le 130000)\) 输出格式: 仅一行一个整数, 为方案数 \( ...

  2. 洛谷P4841 城市规划(生成函数 多项式求逆)

    题意 链接 Sol Orz yyb 一开始想的是直接设\(f_i\)表示\(i\)个点的无向联通图个数,枚举最后一个联通块转移,发现有一种情况转移不到... 正解是先设\(g(n)\)表示\(n\)个 ...

  3. 洛谷P4841 城市规划 [生成函数,NTT]

    传送门 题意简述:求\(n​\)个点的简单无向连通图的数量\(\mod \;1004535809​\),\(n \leq 130000​\) 经典好题呀!这里介绍两种做法:多项式求逆.多项式求对数 先 ...

  4. 洛谷 P4841 城市规划

    构造简单无向图的EGF: \[ G(x)=\sum_{i}^{\infty}2^{\binom{i}{2}}\cdot\frac{x^i}{i!} \] 构造简单无向连通图的EGF: \[ F(x)= ...

  5. [洛谷P4841]城市规划

    题目大意:求$n$个点的带标号的无向连通图的个数 题解:令$F(x)$为带标号无向连通图个数生成函数,$G(x)$为带标号无向图个数生成函数 那么$G(x) = \sum_{i=0}^{\infty} ...

  6. 洛谷P4841 城市规划(多项式求逆)

    传送门 这题太珂怕了……如果是我的话完全想不出来…… 题解 //minamoto #include<iostream> #include<cstdio> #include< ...

  7. [洛谷P3761] [TJOI2017]城市

    洛谷题目链接:[TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速 ...

  8. 【洛谷3343_BZOJ3925】[ZJOI2015]地震后的幻想乡(状压 DP_期望)

    题目: 洛谷 3343 BZOJ 3925 分析: 谁给我说这是个期望概率神题的,明明没太大关系好吧 「提示」里那个结论哪天想起来再问 Jumpmelon 怎么证. 首先,由于开始修路前 \(e_i\ ...

  9. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

随机推荐

  1. java笔试之字符逆序(二)

    与字符逆序(一)不同,句子逆序,单词顺序.例如:I am a student 输出为student a am I. 想法:先字符串句子逆序,然后针对每个单词再逆序一遍. package test; i ...

  2. xcart-子分类/语言不显示

    由于数据库的版本不同,表名会区分大小写的情况,这样就导致xcart语言相关的信息显示不出来,此时只需更改根目录下的init.php文件,如下: 改成小写的就OK了.

  3. Ansible-playbook简单应用的几个实例

    ①ansible-playbook的循环: 重复执行某任务:对迭代项的引用,固定变量名为“item”,而后要在task中使用with_items给定要迭代的元素列表,列表方法:字符串/字典(类似jso ...

  4. LoadRunner函数的介绍

    LoadRunner函数的介绍 LoadRunner函数 一:通用函数 LoadRunner的通用函数以lr为前缀,可以在任何协议中使用.可以如下分类: 信息相关的函数: lr_error_messa ...

  5. 数据结构_冒泡排序(python)

    1.核心思想:比较两个元素,如果前一个比后一个大则进行交换,经过对每个元素的比较,最后最大的元素被放在在最后位置 操作方法: 外层正常for循环遍历,到n-1位,内层for循环相邻两个数比较大小,小数 ...

  6. Django关于migrate无效的问题

    目录 django关于manage.py migrate无效的问题解决 django关于manage.py migrate无效的问题解决 问题描述: 对于django已有的model,修改之后,想重新 ...

  7. 使用vue-awesome-swiper滑块插件

    基于之前写的vue2.0 + vue-cli + webpack 搭建项目( vue-awesome-swiper版本:3.1.3 ,swiper4,如果成功后没报错,但不显示分页样式,可能版本对不上 ...

  8. Android基础控件ProgressBar进度条的使用

    1.简介 ProgressBar继承与View类,直接子类有AbsSeekBar和ContentLoadingProgressBar, 其中AbsSeekBar的子类有SeekBar和RatingBa ...

  9. 移动端开发框架Zepto.js

    一.概述 Zepto.js是一个轻量的js库,它与jQuery有类似的API. zepto的设计目的是不到10K的通用库,快速下载,有一个熟悉的api-->精力专注在开发上. 流行起来的原因:轻 ...

  10. PAT甲级——A1086 Tree Traversals Again

    An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example ...