Codeforces Round #791 (Div. 2) C. Rooks Defenders(树状数组)
https://codeforces.com/contest/1679/problem/C
您有一个大小为n×n的正方形棋盘。行从上到下编号为1到n,列从左到右编号为1到n。因此,每个单元格用一对整数(x,y) (1≤x,y≤n)表示,其中x是行号,y是列号。
您必须执行三种类型的q查询:
在单元格(x,y)中放一辆新车。
从单元格(x,y)中移除一辆车。可以保证车以前被放在这个棋盘里。
检查棋盘的子矩形(x1,y1)(x2,y2)的每个格子是否受到至少一辆车的攻击。
Subrectangle是一组单元格(x,y ),每个单元格满足两个条件:x1≤x≤x2,y1≤y≤y2。
回想一下,如果a=c或b=d,单元格(a,b)受到放置在单元格(c,d)中的车的攻击。特别是,包含车的单元格受到该车的攻击。
投入
第一行包含两个整数n和q (1≤n≤10^5,1≤q≤2⋅10^5) —分别是棋盘的大小和查询的次数。
以下q行中的每一行都包含一个查询的描述。描述以整数t (t∈{1,2,3})开始,表示查询的类型:
如果t=1,则接下来是两个整数x和y(1≤x,y≤n) —新车应该放入的单元格的坐标。保证在给定的查询时刻,单元格(x,y)中没有车。
如果t=2,则接下来是两个整数x和y(1≤x,y≤n) —要从中移除车的像元的坐标。在给定的查询时刻,保证在单元格(x,y)中有一辆车。
如果t=3,则接下来是四个整数x1、y1、x2和y2(1≤x1≤x2≤n,1≤y1≤y2≤n) — subrectangle,以检查其中的每个单元是否受到至少一辆车的攻击。
保证在q个查询中至少有一个第三种类型的查询。
输出
在单独一行中打印第三种类型的每个查询的答案。如果子矩形的每个格子至少被一辆车攻击,打印“Yes”(不带引号)。
否则打印“No”(不带引号)。
input
8 10
1 2 4
3 6 2 7 2
1 3 2
3 6 2 7 2
1 4 3
3 2 6 4 8
2 4 3
3 2 6 4 8
1 4 8
3 2 6 4 8
output
No
Yes
Yes
No
Yes
树状数组板子题,但是这个题目因为涉及到行和列,所以就需要开两个树,往板子里多加入一个参数即可
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=200200;
int n,q;
int r[N],c[N];//行r 列c
int tx[N],ty[N];//tr[N]
int lowbit(int x)
{
return x&-x;
}
void add(int tr[],int x,int v)//为什么要加第一个东西?这是因为有行有列,它其实是有两棵树
{
for(int i=x;i<=n;i+=lowbit(i))
tr[i]+=v;
}
int query(int tr[],int x)
{
int res=0;
for(int i=x;i>=1;i-=lowbit(i))
res+=tr[i];
return res;
}
int main()
{
cin.tie(0); cout.tie(0); ios::sync_with_stdio(0);
cin>>n>>q;
int op,x1,y1,x2,y2;
while(q--)
{
cin>>op;
if(op==1)
{
cin>>x1>>y1;
r[x1]++; //x1这行加一辆车
c[y1]++; //y1这列加一辆车
if(r[x1]==1) add(tx,x1,1);
if(c[y1]==1) add(ty,y1,1);
}
else if(op==2)
{
cin>>x1>>y1;
r[x1]--; //x1这行删掉一辆车
c[y1]--; //y1这列删掉一辆车
if(r[x1]==0) add(tx,x1,-1);
if(c[y1]==0) add(ty,y1,-1);
}
else if(op==3)
{
cin>>x1>>y1>>x2>>y2;
//只要横的每一行都有或者是属的每一列都有车,那么就可以
if(query(tx,x2)-query(tx,x1-1)==(x2-x1+1)||query(ty,y2)-query(ty,y1-1)==(y2-y1+1))
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
}
return 0;
}