CF1379F2 Chess Strikes Back (hard version)

CF1379F2 Chess Strikes Back (hard version)

究极无敌超有趣线段树!

把整个棋盘分成 \(n \times m\)\(2 \times 2\) 的大方格,不难发现每个大格子必须有一个格子放国王。

可以发现有四种大方格:

1、两个白格都可用。

2、只有左上角可用,记左上角格子为 \(a\)

3、只有右下角可用,记左上角格子为 \(b\)

4、两个白格都不可用。若存在则没有可行方案。

发现当存在 \(a\) 在相邻 \(b\) 的右边或右下角,则不可行。

进一步推广,发现不存在可行方案当且仅当:存在一个 \(a\)\(b\) 的右下方(只要横纵坐标都大于即可)

考虑线段树维护。把整个棋盘先压成 \(n \times m\) 的大方格棋盘,然后对行建树,记录每一行列数最小的 \(b\) 和列数最大的 \(a\),分别记作 \(mn_i\)\(mx_i\)(用 set 维护),然后在线段树上维护 \(mn_i\) 的前缀最小和 \(mx_i\) 的后缀最大。最后只需要判断存不存在较上部分的前缀最小 \(\lt\) 较下部分的后缀最大即可。时间复杂度 \(O(n\log n)\)

至于影响可撤销,其实只需要开个 map 记录一下就可以了。

#include<bits/stdc++.h>
#define F(i, l, r) for(int i(l); i <= (r); ++ i)
#define G(i, r, l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
const int N = 3e5; 
const int inf = 1e9;
char buf[100], *p1 = buf, *p2 = buf;
inline int gc(){ return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100,stdin),p1==p2)?EOF:*p1++; }
inline int rd(){
	int x = 0; char ch;
	while(!isdigit(ch = gc()));
	do x = (x << 3) + (x << 1) + (ch ^ 48); while(isdigit(ch = gc()));
	return x;
}
set<int> a[N], b[N];
map<pair<int, int>, int>mp;
int tag[N * 4], mx[N * 4], mn[N * 4];
int n, m, Q; 
void pushup(int u){
	mx[u] = max(mx[u * 2], mx[u * 2 + 1]);
	mn[u] = min(mn[u * 2], mn[u * 2 + 1]);
	if(tag[u * 2] || tag[u * 2 + 1]) tag[u] = 1;
	else if(mn[u * 2] <= mx[u * 2 + 1]) tag[u] = 1;
	else tag[u] = 0;
}
void build(int u, int l, int r){
	if(l == r) {
		mx[u] = 0;
		mn[u] = inf;
		tag[u] = 0;
		return ;	
	}
	int mid = (l + r) / 2;
	build(u * 2, l, mid);
	build(u * 2 + 1, mid + 1, r);
	pushup(u);
}
void update(int u, int l, int r, int x){
	if(l == r){
		mx[u] = *a[l].rbegin();
		mn[u] = *b[l].begin();
		if(mn[u] <= mx[u]) tag[u] = 1;
		else tag[u] = 0;
		return ;
	}
	int mid = (l + r) / 2;
	if(x <= mid) update(u * 2, l, mid, x);
	else update(u * 2 + 1, mid + 1, r, x);
	pushup(u);
}
signed main(){
	n = rd(), m = rd(), Q = rd();
	F(i, 1, n){
		a[i].insert(0);
		b[i].insert(inf);
	}
	build(1, 1, n);
	while(Q --){
		int x = rd() + 1, y = rd() + 1;
		pair<int, int> o = make_pair(x, y);
		if(x % 2 == 1){
			if(mp[o]== 0){
				a[x / 2].insert(y / 2); 	
				mp[o] = 1;
			}
			else{
				a[x / 2].erase(y / 2);
				mp[o] = 0;
			}
		}
		else{
			if(mp[o] == 0){
				b[x / 2].insert(y / 2);
				mp[o] = 1;
			}
			else{
				b[x / 2].erase(y / 2);
				mp[o] = 0;
			}
		}
		update(1, 1, n, x / 2);
		if(!tag[1]){
			puts("YES");
		}
		else{
			puts("NO");
		} 
	}
	return fflush(0), 0;
}
posted @ 2025-08-02 18:05  superl61  阅读(5)  评论(0)    收藏  举报