CF817F MEX Queries

CF817F MEX Queries

洛谷传送门

题目描述

You are given a set of integer numbers, initially it is empty. You should perform nn queries.

There are three different types of queries:

  • 1 ll rr — Add all missing numbers from the interval [l,r][l,r]
  • 2 ll rr — Remove all present numbers from the interval [l,r][l,r]
  • 3 ll rr — Invert the interval [l,r][l,r] — add all missing and remove all present numbers from the interval [l,r][l,r]

After each query you should output MEX of the set — the smallest positive (MEX >=1>=1 ) integer number which is not presented in the set.

输入格式

The first line contains one integer number nn ( 1<=n<=10^{5}1<=n<=105 ).

Next nn lines contain three integer numbers t,l,rt,l,r ( 1<=t<=3,1<=l<=r<=10^{18}1<=t<=3,1<=l<=r<=1018 ) — type of the query, left and right bounds.

输出格式

Print MEX of the set after each query.

题意翻译

  • 维护一个集合,初始为空。

  • 33

    种操作:

    1. 把 [l,r][l,r] 中在集合中没有出现过的数添加到集合中。
    2. 把 [l,r][l,r] 中在集合中出现过的数从集合中删掉。
    3. 把 [l,r][l,r] 中在集合中没有出现过的数添加到集合中,并把 [l,r][l,r] 中在集合中出现过的数从集合中删掉。
  • 每次操作后输出集合的 operatorname{MEX}MEX —— 在集合中没有出现过的最小正整数。

  • 1le nle 10^51≤n≤105,1le lle rle 10^{18}1≤lr≤1018。


题解:

线段树+离散化。

但是并不是裸的叠加。

从头开始思考,展现一下思路过程:首先要维护三种操作,区间置零,区间置1,区间反转,并输出从左到右第一个0的位置。

区间操作必然考虑线段树,但是这个值域维护令人望而却步,但是这么大的值域需要离散化已经是套路的东西了。所以直接把其排序去重映射到一个有限值域中,在这个有限值域建线段树,最后返回的值再映射回去就好了。

然后思考如何维护这几种操作。区间赋值可以打lazy标记,区间反转同样可以打反转标记。打多重lazy标记的时候一定要考虑好标记间的相互影响,换言之,就是两种标记下传的先后问题。那么我们考虑:

区间赋值,之前的反转标记就会失效。区间反转,之前的赋值标记就会取反。它们之间没有先后的顺序,只是每次打新标记的时候直接重新赋值另一种标记就好。

至于求MEX值,很多大佬用了线段树+二分。但是没有必要,只需要先查左子树后查右子树,就可以找到最左的节点。有人说这是贪心,勉强算吧,小贪心?

之后是本题坑点:离散化要把r+1也离散进去。为什么呢?着重讲一讲:因为我们本来想维护值域,但是因为值域太宽广了,所以要离散化。但是并不是所有的都可以离散化。仔细思考:这道题,我们把([l,r])进行离散操作,这个([l,r])就有可能连成一起。那么假如我们要查询(l,r)中间的数,就查不到。这个时候就不能离散化。

但是为什么这道题可以用离散化呢?就是因为我们是整个区间赋值、反转,所以,可以保证答案肯定不会出现在这些区间内部,因为我们本来就是按块操作的。

但是(r+1)不一样,显然,(r+1)是有可能被算成答案的。所以(r+1)也要离散进去。

就大功告成了。

代码:

#include<cstdio>
#include<algorithm>
#define int long long
#define lson pos<<1
#define rson pos<<1|1
using namespace std;
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int read()
{
	int x=0,f=1;
	char ch=nc();
	while(ch<48||ch>57)
		if(ch=='-')
			f=-1,ch=nc();
	while(ch>=48&&ch<=57)
		x=x*10+ch-48,ch=nc();
	return x*f;
}
const int maxn=1e5+5;
int n;
int opt[maxn],l[maxn],r[maxn];
int a[maxn<<2],cnt;
int sum[maxn<<4],lazy[maxn<<4],rev[maxn<<4];
//sum求和,lazy赋值,rev反转
void pushup(int pos)
{
	sum[pos]=sum[lson]+sum[rson];
}
void build(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	lazy[pos]=-1;
	if(l==r)
		return;
	build(lson,l,mid);
	build(rson,mid+1,r);
}
void mark(int pos,int l,int r,int k)
{
	if(k==1)
	{
		sum[pos]=(r-l+1);   
		lazy[pos]=1;
		rev[pos]=0;
	}
	else if(k==2)
	{
		lazy[pos]=0;
		sum[pos]=0;
		rev[pos]=0;
	}
	else
	{
		if(lazy[pos]!=-1)
			lazy[pos]^=1;
		else
			rev[pos]^=1;
		sum[pos]=(r-l+1)-sum[pos];
	}
}
void pushdown(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	if(lazy[pos]==1)
	{
		mark(lson,l,mid,1);
		mark(rson,mid+1,r,1);
		lazy[pos]=-1;
	}
	else if(lazy[pos]==0)
	{
		mark(lson,l,mid,2);
		mark(rson,mid+1,r,2);
		lazy[pos]=-1;
	}
	if(rev[pos])
	{
		mark(lson,l,mid,3);
		mark(rson,mid+1,r,3);
		rev[pos]=0;
	}
}
void update(int pos,int l,int r,int x,int y,int k)
{
	int mid=(l+r)>>1;
	if(l==r)
	{
		if(k==1)
			sum[pos]=1;
		else if(k==2)
			sum[pos]=0;
		else
			sum[pos]^=1;
		return;
	}
	if(x<=l && r<=y)
	{
		mark(pos,l,r,k);
		return;
	}
	pushdown(pos,l,r);
	if(x<=mid)
		update(lson,l,mid,x,y,k);
	if(y>mid)
		update(rson,mid+1,r,x,y,k);
	pushup(pos);
}
int query(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	if(l==r)
		return l;
	pushdown(pos,l,r);
	if(sum[lson]<(mid-l+1))
		return query(lson,l,mid);
	else
		return query(rson,mid+1,r);
}
signed main()
{
	n=read();
	a[++cnt]=1;
	for(int i=1;i<=n;i++)
	{
		opt[i]=read();l[i]=read();r[i]=read();
		a[++cnt]=l[i];a[++cnt]=r[i];a[++cnt]=r[i]+1;
	}
	sort(a+1,a+cnt+1);
	cnt=unique(a+1,a+cnt+1)-(a+1);
	build(1,1,cnt);
	for(int i=1;i<=n;i++)
	{
		l[i]=lower_bound(a+1,a+cnt+1,l[i])-a;
		r[i]=lower_bound(a+1,a+cnt+1,r[i])-a;
		update(1,1,cnt,l[i],r[i],opt[i]);
		printf("%lld
",a[query(1,1,cnt)]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/fusiwei/p/13965392.html