C Rooks Defenders
点此进入题面
题意:
给出一个棋盘,每次 有两种操作:
-
① 向某一格放入一个石头(在某一格放入石头,则 该行该列都会受到攻击)
-
② 询问某个矩阵中是否所有方格都受到了攻击。
思路:
行列分开讨论,使用 两个一维树状数组 分别维护 行(tI)、列(tII) 的 单点修改,区间查询 功能(行、列 是否有被攻击,也可直接用布尔数组)
用 Hash 表 分别记录 行(hahI[] 数组)、列(hahII[] 数组) 的石头数量,
对于 某一行 或 某一列
-
如果 从没有石头到有石头,则 对于行或列 单点 +1:addI(x, 1), addII(y, 1);
-
如果 从有石头到没有石头,则 对于行或列 单点 -1:addI(x, -1), addII(y, -1);
注意:判断时只需要行列其中之一满足即可。
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int, int> pii;
typedef map<int, int> mi;
typedef vector<ll> vll;
typedef pair<ll, ll> pll;
#define pb push_back
#define pp pop_back
#define x first
#define y second
const int N = 1e5 + 10;
int hahI[N], hahII[N];
int tI[N], tII[N];
void Clear()
{
memset(hahI, 0, sizeof hahI);
memset(hahII, 0, sizeof hahII);
memset(tI, 0, sizeof tI);
memset(tII, 0, sizeof tII);
}
inline int lowbit(int x) {
return x & (-x);
}
void addI(int x, int v)
{
for (; x <= N; x += lowbit(x)) tI[x] += v;
}
void addII(int y, int v)
{
for (; y <= N; y += lowbit(y)) tII[y] += v;
}
int askI(int x)
{
int res = 0;
for (int i = x; i > 0; i -= lowbit(i)) res += tI[i];
return res;
}
int askII(int y)
{
int res = 0;
for (int i = y; i > 0; i -= lowbit(i)) res += tII[i];
return res;
}
signed main()
{
int T = 1;
//cin>>T;
while (T--)
{
Clear();
int n, q; scanf("%lld%lld", &n, &q);
while (q--)
{
int op, x, y; scanf("%lld%lld%lld", &op, &x, &y);
if (op == 1) //put
{
hahI[x] ++, hahII[y] ++;
if (hahI[x] == 1) addI(x, 1);
if (hahII[y] == 1) addII(y, 1);
}
else if (op == 2) //remove
{
hahI[x] --, hahII[y] --;
if (!hahI[x]) addI(x, -1);
if (!hahII[y]) addII(y, -1);
}
else //query
{
int a, b; scanf("%lld%lld", &a, &b);
int t1 = askI(a) - askI(x - 1);
int t2 = askII(b) - askII(y - 1);
if (t1 == (a - x + 1) || t2 == (b - y + 1)) puts("YES"); //显然行、列 其一满足即可
else puts("NO");
}
}
}
return 0;
}