[思维] [树形数据结构] CF1379F1 Chess Strikes Back (easy version)
注意到棋盘大小为 $2n\times 2m$,共 $2nm$ 个白格,同时国王数量为 $nm$,尝试将 $2$ 个国王捆绑在一块,即将棋盘均匀划分为若干个 $2\times 2$ 大小的大格子。
在此基础上观察,显然同一个大格子内的两个白格不能同时放置国王,同时大格子数量为 $nm$,因此问题转化为判定能否使得所有大格子都有一个国王,这是此题不易想到但是很必要的一步。
初始情况下必定满足条件,那么移去一个白格,显然这个白格所属的大格子只能将国王安置在另一个白格上。
对移去的白格在大格子中的位置分类讨论,设左上角的被移去,则当前大格子正下方和正右方的大格子的左上角也无法放置,也就是说这个两个大格子的安置方案也被唯一确定了。以此类推,可以发现当前大格子到棋盘右下角的矩形内的所有大格子都无法将国王安置到左上白格。
同理,假如移去白格位于右下,则当前大格子到棋盘左上角的矩形内的所有大格子都无法将国王安置到右下白格。
考虑什么时候无解,即存在某个大格子的左上、右下白格均无法安置国王。换句话说,我们定义左上白格被移去的大格子为 $1$ 类格子,右下白格被移去的为 $2$ 类白格,那么无解当且仅当存在 $2$ 类格子在 $1$ 类格子的右下方。
这个问题可用树状数组解决。若当前操作的是 $2$ 格子 $x,y$,则查找 $x$ 坐标在 $[1,x]$ 内的、纵坐标最小的大格子并进行比较,之后将当前格子插入树状数组即可。$1$ 类格子同理。
复杂度 $O(q\log n)$。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5, inf = 1e9;
int n, m, q, x, y, xx, yy;
bool flag;
namespace BIT{
int t[N], t2[N];
inline void init(int t[]) {for(int i = 0; i < N; ++i) t[i] = inf;}
inline void upd(int t[], int a, int k) {for(; a < N; a += a & (-a)) t[a] = min(t[a], k);}
inline int qry(int t[], int a) {int res = inf; for(; a > 0; a -= a & (-a)) res = min(res, t[a]); return res;}
}
using namespace BIT;
signed main(){
init(t), init(t2);
cin >> n >> m >> q;
while(q--){
scanf("%d%d", &x, &y);
xx = (x + 1) >> 1, yy = (y + 1) >> 1;
if(x & 1){
if(-qry(t2, n - xx + 1) >= yy) flag = true;
upd(t, xx, yy);
}
else{
if(qry(t, xx) <= yy) flag = true;
upd(t2, n - xx + 1, -yy);
}
(flag == true) ? printf("NO\n") : printf("YES\n");
}
return 0;
}