Codeforces Round #791 (Div. 2) C - Rooks Defenders(树状数组)

题目来源

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值