题意:给你一个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. nvelocity的Foreach 中使用DataTable数据

    原文:nvelocity的Foreach 中使用DataTable数据 tripDetailList是一个DataTable类型的数据,Logo.TripTypeName.TipTypePrice等为 ...

  2. array_map、array_walk、array_filter三个函数的区别

    array_walk --- 使自定的函数能处理数组的每个元素 bool array_walk ( array &array, callback funcname [, mixed userd ...

  3. 【案例】DIV随鼠标移动而移动

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. No packages marked for update

    问题:用yum安装docker,更新yum存储时,报以下错误,导致yum坏了 [root@localhost yum.repos.d]# vi docker.repo [root@localhost ...

  5. HNOI2018思记

    4-13 顺顺利利到了湖南.晚上认真研读cf毒瘤题题解,未果. 发现这里含铁丰富的高温多雨式红土地.以及窗户特别深,总有一圈小阳台的房子,门楣深邃如瞳. 看了一波miaom的ZJOI游记,思考了一下解 ...

  6. Apache服务器中运行CGI程序的方法,文中以Perl脚本作为示例

    关于apache与CGI在这里就不解释了. 1.apache下面以2.0.63为例介绍运行CGI程序的配置.(http://www.nklsyy.com) 2.下载Windows下的Perl解释器Ac ...

  7. ES6 学习笔记(基础)

    书链接:http://es6.ruanyifeng.com/ #.let let 不存在“变量提升” 暂时性死区(即:let 所定义的变量在局部作用域中不受外界影响) var tmp = 123; i ...

  8. 【转载】unittest总结

    本文转载链接:http://www.cnblogs.com/yufeihlf/p/5707929.html unittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执 ...

  9. C# 判断当前请求是GET、还是POST ?

    方法一: HttpContext.Current.Request.RequestType == "POST"   //当前请求为:POST 方法二: if(Request.Serv ...

  10. python-web-selenium模拟控制浏览器

    用 selenium 模块控制浏览器 启动 selenium 控制的浏览器 from selenium import webdriver brower = webdriver.Firefox() br ...