[cf1642E]Anonymity Is Important

Description

q次在线操作,实时告诉区间[l,r]有/没有病人,询问病人x是否一定患病/无病。

Solution

用时间戳在线转离线。
一个病人无病当且仅当他属于某个无病区间。
一个病人一定有病当且仅当他在某个除了他都没病的有病区间内。
否则不确定是否有病。
可以发现,有病区间互不干扰。
只需先处理出无病的病人,记录他们最早被确定无病的时间。
再对于每个有病区间求是否只有一个病人可能有病,记录病人最早被确定有病的时间。
对于每个询问,只要晚于最早被确定有/无病的时间,就可以确定,否则为不确定。

处理方法一

用线段树记录每个区间是否全为有病/除了一个外其余全都有病,记录每个区间的时间戳最大值。

处理方法二

用set记录可能有病的病人。
依次删去无病区间的点,记录他们最早被确定无病的时间。
再对每个有病区间求区间内是否存在第二个可能有病的人,更新病人最早被确定有病的时间。

#include<bits/stdc++.h>
using namespace std;
const int N=200005,M=800005;
struct patient{
	int ty;//1:YES,sick; 0:N/A:0; -1,NO.not sick
	int t;
}ans[N];
struct SegmentTree{
	int t;
}lt[M];
struct update{
	int l,r,t;
}ud1[N],ud2[N];
struct query{
	int x,t;
}q[N];
int n,m,m1,m2,t;
set<int> s;
void build(int u,int l,int r){
	if(l==r){
		lt[u].t=ans[l].t;
		return;
	}
	int mid=(l+r)>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	lt[u].t=max(lt[u<<1].t,lt[u<<1|1].t);
}
int ask(int u,int lef,int rig,int l,int r){
	if(l<=lef&&rig<=r)
		return lt[u].t;
	int ret=0,mid=(lef+rig)>>1;
	if(l<=mid) ret=max(ret,ask(u<<1,lef,mid,l,r));
	if(r>mid) ret=max(ret,ask(u<<1|1,mid+1,rig,l,r));
	return ret;
}
int main(){
	scanf("%d%d",&n,&t);
	for(int i=1,ty,l,r,x;i<=t;++i){
		scanf("%d",&ty);
		if(ty){
			scanf("%d",&x);
			q[++m]=(query){x,i};
		}
		else{
			scanf("%d%d%d",&l,&r,&x);
			if(x) ud1[++m1]=(update){l,r,i};
			else ud2[++m2]=(update){l,r,i};
		}
	}
	for(int i=1;i<=n;++i)
		s.insert(i);
	for(int i=1;i<=m2;++i){
		set<int>::iterator u=s.lower_bound(ud2[i].l);
		while(u!=s.end()&&(*u)<=ud2[i].r){
			ans[*u]=(patient){-1,ud2[i].t};
			s.erase(u++);
		}
	}
	build(1,1,n);
	for(int i=1;i<=m1;++i){
		if(ud1[i].l==ud1[i].r){
			if(!ans[ud1[i].l].ty||ud1[i].t<ans[ud1[i].l].t)
				ans[ud1[i].l]=(patient){1,ud1[i].t};
			continue;
		}
		set<int>::iterator u1=s.lower_bound(ud1[i].l);
		if(u1==s.end()) continue;
		set<int>::iterator u2=u1;++u2;
		if((*u1)<=ud1[i].r&&(u2==s.end()||(*u2)>ud1[i].r)){
			int t=max(ud1[i].t,ask(1,1,n,ud1[i].l,ud1[i].r));
			if(!ans[*u1].ty||t<ans[*u1].t) ans[*u1]=(patient){1,t};
		}
	}
	for(int i=1;i<=m;++i){
		if(!ans[q[i].x].ty||ans[q[i].x].t>q[i].t)
			printf("N/A\n");
		else if(ans[q[i].x].ty>0) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

posted @ 2022-02-26 22:20  Aireen_Ye  阅读(81)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.