题意: n ∗ m , n , m ≤ 1 e 3 n*m,n,m\le 1e3 n∗m,n,m≤1e3 的矩阵,矩阵赋 1,查询 1 的连通块个数, q ≤ 3 e 4 q\le3e4 q≤3e4 次修改
想到用并查集维护连通块,每次暴力将矩阵中的合并肯定要凉
于是把矩阵中为 0 的踢出来合并
考虑到 n q nq nq 可能可以卡过,于是用 s e t set set 维护每一行的为 0 0 0 的点,每次踢出来暴力改成 1 并与周围的合并
显然每个点只会出来一次,复杂度 O ( q n l o g ( n ) + n 2 l o g ( n ) ) O(qnlog(n)+n^2log(n)) O(qnlog(n)+n2log(n))
#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch - '0'), ch = getchar();
return cnt * f;
}
cs int N = 1005;
int n, m, q, sum;
char mp[N][N];
set<int> S[N];
typedef set<int>::iterator Int;
int idx(int x, int y){ return (x - 1) * m + y;}
int fa[N * N];
int find(int x){ return x == fa[x] ? x : fa[x] = find(fa[x]);}
void merge(int x, int y){
++sum;
if(x > 1 && mp[x - 1][y] == '1'){
int fx = find(idx(x, y)), fy = find(idx(x - 1, y));
if(fx ^ fy) fa[fx] = fy, --sum;
}
if(y > 1 && mp[x][y - 1] == '1'){
int fx = find(idx(x, y)), fy = find(idx(x, y - 1));
if(fx ^ fy) fa[fx] = fy, --sum;
}
if(x < n && mp[x + 1][y] == '1'){
int fx = find(idx(x, y)), fy = find(idx(x +1, y));
if(fx ^ fy) fa[fx] = fy, --sum;
}
if(y < m && mp[x][y + 1] == '1'){
int fx = find(idx(x, y)), fy = find(idx(x, y + 1));
if(fx ^ fy) fa[fx] = fy, --sum;
}
}
int main(){
n = read(), m = read();
for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) fa[idx(i, j)] = idx(i, j);
for(int i = 1; i <= n; i++){
scanf("%s", mp[i] + 1);
for(int j = 1; j <= m; j++){
if(mp[i][j] == '0') S[j].insert(i);
else merge(i, j);
}
}
q = read();
while(q--){
int x1 = read(), y1 = read(), x2 = read(), y2 = read();
for(int i = y1; i <= y2; i++){
int top = 0;
Int it = S[i].lower_bound(x1);
while(it != S[i].end()){
int nx = *it;
if(nx > x2) break;
merge(nx, i); mp[nx][i] = '1';
S[i].erase(it++);
}
}
cout << sum << '\n';
} return 0;
}
以下是口胡时间 「蓬莱的弹枝 -七色的弹幕-」
高级数据结构不如暴力数据结构 ---- ldx 神仙
考虑分块
首先挪一位,就是把一个块的最前放到一个块的最后,可以每个块维护一个队列
两头暴力重构
全部加 1 就是打一个 t a g tag tag,然后挪块的时候可能需要改一下 t a g tag tag
对于 3,每个块维护一个桶,装 a i a_i ai 的出现次数,非常暴力,查询每个块扫一遍,如果有就块内扫一遍
然后 a i ≤ 1 e 5 a_i\le 1e5 ai≤1e5, Δ ≤ 1 e 5 \Delta\le 1e5 Δ≤1e5,数最大是 2 e 5 2e5 2e5,但挪块可能变负,平移一波开到 3 e 5 3e5 3e5
算了一些块最多 200 200 200 个,大小 500 500 500 左右