题意:给你一个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. 面试系列16 redis的持久化

    1.RDB和AOF两种持久化机制的介绍 RDB持久化机制,对redis中的数据执行周期性的持久化 AOF机制对每条写入命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的 ...

  2. eclipse-帮助文档

    Eclipse开发环境配置 1.         java环境 安装 本系统使用java6开发,老师使用1.6.0 _45版本开发,如下图所示: “开发工具”目录提供了1.6.0 _45版本32位和6 ...

  3. csps-s模拟测试62,63Graph,Permutation,Tree,Game题解

    题面:https://www.cnblogs.com/Juve/articles/11631298.html permutation: 参考:https://www.cnblogs.com/clno1 ...

  4. 18多校8th

    a-容斥原理(带限制的不定方程) #include<bits/stdc++.h> using namespace std; #define mod 998244353 #define ll ...

  5. JavaSE_12_Properties类和缓冲流

    1.Properties类 java.util.Properties 继承于Hashtable ,来表示一个持久的属性集.它使用键值结构存储数据,每个键及其对应值都是一个字符串.该类也被许多Java类 ...

  6. lvs + keepalived + nginx + tomcat高可用负载反向代理服务器配置(二) LVS+Keepalived

    一.安装ipvs sudo apt-get install ipvsadm 二.安装keepalived sudo apt-get install keepalived 三.创建keepalived. ...

  7. 84 落单的数 III

    原题网址:http://www.lintcode.com/zh-cn/problem/single-number-iii/# 给出2*n + 2个的数字,除其中两个数字之外其他每个数字均出现两次,找到 ...

  8. LintCode刷题笔记-- A+B problem

    标签: 位运算 描述 Write a function that add two numbers A and B. You should not use + or any arithmetic ope ...

  9. PKU--1976 A Mini Locomotive (01背包)

    题目http://poj.org/problem?id=1976 分析:给n个数,求连续3段和的最大值. 这个题目的思考方式很像背包问题. dp[i][j]表示前i个数字,放在j段的最大值. 如果选了 ...

  10. 11-6-es5选项卡

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