题面
🔗
题解
一个矩形,我们可以翻译成只有四个角的非空网格图形。
一个非空的任意网格图形至少有四个角,所以我们只需要维护每个前缀的角的数量,以及角的数量达到最小值的位置个数。
由于不同位置的角一共有 O ( H W ) O(HW) O(HW) 个,每次询问涉及的角有 O ( 1 ) O(1) O(1) 个,完全可以对每个角分别讨论。
假设一个角长这样(把 A 围起来,与 BCD 相邻):
A|B
-·
C D
那么它存在的条件是满足以下任意一个命题
- A 在前缀中,BC 不在前缀中(前缀端点在区间 [ A , min ( B , C ) − 1 ] [A,\min(B,C)-1] [A,min(B,C)−1])
- A 不在前缀中,BC 都在前缀中(前缀端点在区间 [ max ( B , C ) , A − 1 ] [\max(B,C),A-1] [max(B,C),A−1])
在对应区间做区间加减就可以了,最终全局查询。
时间复杂度 O ( H W log 2 ( H W ) + Q log 2 ( H W ) ) O(HW\log_2(HW)+Q\log_2(HW)) O(HWlog2(HW)+Qlog2(HW)) ,常数较大。
CODE
一开始没看到标号在 0 ∼ k − 1 0\sim k-1 0∼k−1 之间,以为标号连续就行了,把我给吓傻了
#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<random>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 1000005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
int xchar() {
static const int maxn = 1000000;
static char b[maxn];
static int pos = 0,len = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
//#define getchar() xchar()
LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}
int n,m,s,o,k;
int x[MAXN],y[MAXN],N;
struct it{
int mi,nm;
it(){mi=0x3f3f3f3f;nm=0;}
}tre[MAXN<<2];
it operator + (it a,int b) {a.mi+=b;return a;}
it& operator += (it &a,int b) {a.mi+=b;return a;}
inline it merg(it a,it b) {
if(a.mi != b.mi) return a.mi < b.mi ? a:b;
a.nm += b.nm; return a;
}
int M,lz[MAXN<<2];
void maketree(int n) {
M = 1; while(M<n+2) M<<=1;
for(int i = 1;i <= n;i ++) tre[M+i].nm = 1,tre[M+i].mi = 0;
for(int i = M-1;i > 0;i --) tre[i] = merg(tre[i<<1],tre[i<<1|1]);
return ;
}
void addtree(int l,int r,int y) {
if(l > r) return ;
for(int s=M+l-1,t=M+r+1;s || t;s >>= 1,t >>= 1) {
if(s<M) tre[s] = merg(tre[s<<1],tre[s<<1|1]) + lz[s];
if(t<M) tre[t] = merg(tre[t<<1],tre[t<<1|1]) + lz[t];
if((s>>1) ^ (t>>1)) {
if(!(s&1)) tre[s^1] += y,lz[s^1] += y;
if(t & 1) tre[t^1] += y,lz[t^1] += y;
}
} return ;
}
it findtree(int l,int r) {
it ls = it(),rs = it(); if(l > r) return ls;
for(int s=M+l-1,t=M+r+1;s || t;s >>= 1,t >>= 1) {
ls += lz[s]; rs += lz[t];
if((s>>1) ^ (t>>1)) {
if(!(s&1)) ls = merg(ls,tre[s^1]);
if(t & 1) rs = merg(rs,tre[t^1]);
}
}return merg(ls,rs);
}
vector<int> a[MAXN];
const int dx[4] = {1,0,-1,0};
const int dy[4] = {0,1,0,-1};
bool f[MAXN];
void addp(int i) {
if(!i || f[i]) return ;
int s = x[i],o = y[i];
for(int j = 0;j < 4;j ++) {
int l = a[s+dx[j]][o+dy[j]],r = a[s+dx[(j+1)&3]][o+dy[(j+1)&3]];
if(!l) l = N+1; if(!r) r = N+1;
addtree(i,min(l,r)-1,1);
addtree(max(l,r),i-1,1);
} f[i] = 1;
return ;
}
void delp(int i) {
if(!i || !f[i]) return ;
int s = x[i],o = y[i];
for(int j = 0;j < 4;j ++) {
int l = a[s+dx[j]][o+dy[j]],r = a[s+dx[(j+1)&3]][o+dy[(j+1)&3]];
if(!l) l = N+1; if(!r) r = N+1;
addtree(i,min(l,r)-1,-1);
addtree(max(l,r),i-1,-1);
} f[i] = 0;
return ;
}
int main() {
n = read(); m = read(); int Q = read();
for(int i = 0;i <= n+1;i ++) {
a[i].resize(m+2);
}
maketree(N=n*m);
for(int i = 1;i <= N;i ++) {
x[i] = read()+1; y[i] = read()+1;
a[x[i]][y[i]] = i;
}
for(int i = 1;i <= N;i ++) addp(i);
for(int i = 1;i <= Q;i ++) {
s = read()+1;o = read()+1;
delp(s); delp(o);
for(int j = 0;j < 4;j ++) {
delp(a[x[s]+dx[j]][y[s]+dy[j]]);
delp(a[x[o]+dx[j]][y[o]+dy[j]]);
}
swap(a[x[s]][y[s]],a[x[o]][y[o]]);
swap(x[s],x[o]); swap(y[s],y[o]);
addp(s); addp(o);
for(int j = 0;j < 4;j ++) {
addp(a[x[s]+dx[j]][y[s]+dy[j]]);
addp(a[x[o]+dx[j]][y[o]+dy[j]]);
}
putnum(tre[1].nm); cout<<endl;
}
return 0;
}