题意:给你一个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. HTML中使用js的三种方式及优缺点介绍

    1.内部js: 在直接在页面的<script></script>标签内写js代码 优点:相对于使用行内js,内部js代码较为集中,与页面结构的实现代码耦合度较低,比较便于维护 ...

  2. iOS开发系列-NSOutputStream

    NSOutputStream 创建一个NSOutputStream实例 - (nullable instancetype)initToFileAtPath:(NSString *)path appen ...

  3. 创建你的 /proc 文件

    一旦你有一个定义好的 read_proc 函数, 你应当连接它到 /proc 层次中的一个入口项. 使用一个 creat_proc_read_entry 调用: struct proc_dir_ent ...

  4. 控制类名(className 属性)设置或返回class属性

    控制类名(className 属性) className 属性设置或返回元素的class 属性. 语法: object.className = classname 作用: 1.获取元素的class 属 ...

  5. 【颓废篇】人生苦短,我用python(一)

    谁渴望来一场华(ang)丽(zang)的python交易! 最近突然产生了系统学习python的想法. 其实自从上次luogu冬日绘板dalao们都在写脚本就有这种想法了. 最近被计算几何势力干翻的我 ...

  6. JavaScript数组的2种定义方式

    JavaScript中没有数组类型,JavaScript中数组是以内置对象的形式存在的. 数组是存储多个值的集合(仓库). JS中定义数组的2种方式: 1.使用new Array()构造函数定义数组 ...

  7. thinkphp 参数绑定

    参数绑定是指绑定一个参数到预处理的SQL语句中的对应命名占位符或问号占位符指定的变量,并且可以提高SQL处理的效率,需要数据库驱动类的支持,目前只有PDO和Sqlsrv驱动支持参数绑定功能. 富瑞华大 ...

  8. vs Code打开新的文件会覆盖窗口中的文件?

    这是因为你单击文件名的缘故,这个是“预览模式”,所以再单击其他文件时,会覆盖当前打开的文件. 如果你要每次都打开新tab,那就双击文件名好了.这个逻辑和sublime是一样的. 补充: 预览模式是现在 ...

  9. 微信公众号 SVG长按互动

    <section class="" style="display: block;width: 100%;height:667px;overflow:hidden;m ...

  10. EF Code First数据库连接配置

    前面几节,使用的都是通过EF Code First创建的新数据库,接下来,将开始使用已存在的数据库. 1.使用配置文件设置数据库连接 App.config 数据库连接字符串的name与Data中Nor ...