Educational Codeforces Round 23 F. MEX Queries(离散化+线段树)

题目链接:http://codeforces.com/contest/817/problem/F


这个题的难度不像是F啊。。。


然而


我好蠢啊。。。


最开始发现,其实很多区间可以合并在一起,就写了一个延时更新的[1,1e18]的线段树,MLE 21到死。。。


后来发现,离散化一下好像很清真啊?


由于只有0和1两个值,然后发现操作3就是个异或的操作,下放的时候可以同时对1的个数和lazy标记同时进行处理。离散化的时候,注意,对于区间[L,R],需要多离散化一个R+1这个节点,因为这个点可能作为某次查询的答案(别问我为啥离散化L-1,大概是蠢吧),然后就是个水题啊?


(那我为什么写了这么久啊?)


代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct seg
{
	ll tot;
	bool rev;
	int lazy;
	bool ro;
	seg *lson,*rson;
	seg(){}
	seg(int _rev):rev(_rev)
	{
		lson=rson=NULL;
		lazy=-1;tot=0;
		ro=false;
	}
	ll gettot()
	{
		return tot;
	}
	void pushup()
	{
		ll ret=0;
		if(lson!=NULL)
			ret+=lson->gettot();
		if(rson!=NULL)
			ret+=rson->gettot();
		tot=ret;
	}
	int getid()
	{
		return lazy^rev;
	}
	void pushlazy(ll l,ll r)
	{
		ll mid=(l+r)>>1;
		if(lson==NULL)
			lson=new seg(0);
		if(rson==NULL)
			rson=new seg(0);
		if(ro)
		{
			lson->rev^=1;lson->ro=!lson->ro;
			lson->tot=(mid-l+1)-lson->tot;
			rson->rev^=1;rson->ro=!rson->ro;
			rson->tot=(r-(mid+1)+1)-rson->tot;
			ro=false;
		}
		if(lazy!=-1)
		{
			lson->lazy=(getid()^lson->rev);
			lson->tot=(mid-l+1)*lson->getid();
			rson->lazy=(getid()^rson->rev);
			rson->tot=(r-(mid+1)+1)*rson->getid();
			lazy=-1;
		}
	}
	void update(ll L,ll R,int val,bool we,ll l,ll r)
	{
		if(L<=l&&r<=R)
		{
			if(!we)
			{
				lazy=val^rev;
				tot=(r-l+1)*getid();
			}
			else
			{
				ro=!ro;
				rev^=1;
				tot=r-l+1-tot;
			}
			return ;
		}
		pushlazy(l,r);
		ll mid=(l+r)>>1;
		if(mid>=L)
		{
			lson->update(L,R,val,we,l,mid);
		}
		if(mid<R)
		{
			rson->update(L,R,val,we,mid+1,r);
		}
		pushup();
	}
	ll query(ll l,ll r)
	{
		if(gettot()==0)
			return l;
		ll mid=(l+r)>>1;
		seg tmp=*this;
		pushlazy(l,r);
		if(lson->gettot()<(mid-l+1))
			return lson->query(l,mid);
		else
			return rson->query(mid+1,r);
	}
}*root;
const int MAXN=1e5+5;
int tot;
ll Hash[MAXN*4];
struct qu
{
	int op;
	ll l,r;
}sv[MAXN];
int fi(ll now)
{
	int ret=lower_bound(Hash,Hash+tot,now)-Hash;
	return ret;
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	root=new seg(0);
	tot=0;
	Hash[tot++]=1000000000000000001LL;
	Hash[tot++]=1;
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int op;
		ll l,r;
		scanf("%d%lld%lld",&sv[i].op,&sv[i].l,&sv[i].r);
		Hash[tot++]=sv[i].l;Hash[tot++]=sv[i].r;
		if(sv[i].l!=1)
			Hash[tot++]=sv[i].l-1;
		Hash[tot++]=sv[i].r+1;
	}
	sort(Hash,Hash+tot);
	tot=unique(Hash,Hash+tot)-Hash;
	for(int i=1;i<=n;i++)
	{
		sv[i].l=fi(sv[i].l);
		sv[i].r=fi(sv[i].r);
	}
	for(int i=1;i<=n;i++)
	{
		if(sv[i].op==1)
		{
			root->update(sv[i].l,sv[i].r,1,false,0,tot-1);
		}
		if(sv[i].op==2)
		{
			root->update(sv[i].l,sv[i].r,0,false,0,tot-1);
		}
		if(sv[i].op==3)
		{
			root->update(sv[i].l,sv[i].r,0,true,0,tot-1);
		}
		int ret=root->query(0,tot-1);
		ll ans;
		ans=Hash[ret];
		printf("%lld\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值