E. Anonymity Is Important

题目链接:

E. Anonymity Is Important

题意

给出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");
				}
			}
		}
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值