This way
现在有一张n*m的棋盘,上面放着k个车,车的攻击范围是它所处的这一行或这一列。
q个询问,每次问你如果只选择一个矩形的范围,每个格子是否都处在被攻击的状态中。
补一下以前没做出来的题目,现在看看发现其实还是蛮简单的。
首先如果每个格子处在被攻击的状态之下,那么要么每行或者每列有一个车。
那么我们就需要一个数据结构能够查询矩形中是否每行或者每列都有车。
很明显直接查是很难的,至少我一下子想不出来。但是我如果从下到上枚举每行,然后查看一个区间内,这条线上面的最近的车的最大值,那就很容易了。
我用set保存每行/每列的所有的车的列号/行号。然后从下到上枚举每行/列然后查询,更新。。。
看着代码很多,但是其实很多都是重复的,或者是模板
#include
using namespace std;
const int N=1e5+5;
setsx[N],sy[N];
int x[N],y[N];
bool ans[N];
struct Query{
int l,r,h,id;
};
vectorq_x[N],q_y[N];
struct node{
int mx[N*4];
void update(int l,int r,int root,int p,int v){
if(l==r){
mx[root]=v;
return ;
}
int mid=l+r>>1;
if(mid>=p)
update(l,mid,root<<1,p,v);
else
update(mid+1,r,root<<1|1,p,v);
mx[root]=max(mx[root<<1],mx[root<<1|1]);
}
int query(int l,int r,int root,int ql,int qr){
if(l>=ql&&r<=qr)
return mx[root];
int ans=0,mid=l+r>>1;
if(mid>=ql)
ans=query(l,mid,root<<1,ql,qr);
if(mid::iterator it=sx[p].lower_bound(i);
if(it!=sx[p].end())
tx.update(1,n,1,p,*it);
else
tx.update(1,n,1,p,1e9);
}
else
tx.update(1,n,1,p,1e9);
}
}
for(auto u:q_x[i])
ans[u.id]=tx.query(1,n,1,u.l,u.r)<=u.h;
}
for(int i=1;i<=m;i++){
if(sy[i].size())
ty.update(1,m,1,i,*sy[i].begin());
else
ty.update(1,m,1,i,1e9);
}
for(int i=1;i<=n;i++){
if(sx[i-1].size()){
for(auto p:sx[i-1]){
if(sy[p].size()){
set::iterator it=sy[p].lower_bound(i);
if(it!=sy[p].end())
ty.update(1,m,1,p,*it);
else
ty.update(1,m,1,p,1e9);
}
else
ty.update(1,m,1,p,1e9);
}
}
for(auto u:q_y[i])
ans[u.id]=max(ans[u.id],ty.query(1,m,1,u.l,u.r)<=u.h);
}
for(int i=1;i<=q;i++)
printf("%s\n",ans[i]?"YES":"NO");
return 0;
}