题目链接:
题意
给出n个人和q次操作。
0 l r x
1 x
当操作类型为0的时候,x=1表示[l,r]内至少有一个病人,x=0表示[l,r]内没有病人
当询问类型为1的时候,给出当前人x有病/无病/不确定的判断。
思路
一开始将1-n插入set中,当某区间内病人个数为0时,从set中将这段区间内的编号都删除。
(二分查找s中第一个大于等于l的值,然后顺序删除直至值大于r)
用map保存至少有一个病人的区间,mp[l]=r表明[l,r]内至少有一个病人。
对每次要新插入的[l,r],如果map中之前已经存在[l',r'],而[l,r]包含[l',r'],则[l,r]为无效信息,因为[l',r']内至少有一个病人了,[l,r]除[l',r']的部分依旧不能确定有没有病人,这个信息等价于没有。
同样地,如果而[l',r']包含[l,r],则要删除map中所有的[l',r']区间。
对于查询,若x不在set中说明x肯定没有病,否则的话,在set中找到x的位置,并得到其前一个和后一个不能确定是否有病的人的编号记为lp和rp,在map中查询第一个左端点大于lp的区间(不会说有某个区间[l,r]满足l>lp并且r<rp,因为set中这段区间里的人都被删掉了,不可能说这段区间至少有一个病人,否则矛盾,所以r是一定大于x的),如果x在这个区间内而rp不在这个区间内,说明x肯定患病,否则的话不能确定x是否有病,输出'N/A'。
样例
代码
#include <bits/stdc++.h>
using namespace std;
set<int> s;
map<int,int> mp;
int n,q;
int main(){
scanf("%d%d",&n,&q);
for(int i=0;i<=n+1;i++)
s.insert(i);
int op,l,r,x;
while(q--){
scanf("%d",&op);
if(op==0){
scanf("%d%d%d",&l,&r,&x);
if(x==0){
while(1){
auto iter=s.lower_bound(l);
if(iter==s.end()||*iter>r)
break;
else
s.erase(iter);
}
}
else{
auto iter=mp.lower_bound(l);
//新给的区间[l,r]如果覆盖map里之间存的某个区间
//这个区间就没有意义
if(iter!=mp.end()&&iter->second<=r){
continue;
}
mp[l]=r;
iter=mp.find(l);
while(iter!=mp.begin()&&prev(iter)->second>=r)
mp.erase(prev(iter));
}
}
else{
scanf("%d",&x);
if(!s.count(x)){
printf("NO\n");
}
else{
auto iter=s.find(x);
int l=*prev(iter),r=*next(iter);
//0和n+1为什么要插入就在这里体现
//当set中x为第一个元素时,*prev(iter)就为0,大于0的区间就可以
auto it=mp.upper_bound(l);
if(it!=mp.end()&&it->first<=x&&it->second<r){
printf("YES\n");
}
else{
printf("N/A\n");
}
}
}
}
}