CodeForces - 817F MEX Queries(线段树lazy序)

14 篇文章 0 订阅
11 篇文章 0 订阅

题目链接:点击查看

题目大意:初始时有一个空的集合,需要执行 n 次操作:

  1. 1 l r:将区间 [ l , r ] 内未出现的数加入到集合中
  2. 2 l r:将区间 [ l , r ] 内出现的数字全部删除
  3. 3 l r:将区间 [ l , r ] 内未出现的数加入到集合中,同时将区间 [ l , r ] 内出现过的数字全部删除

每次操作后取集合的 MEX

题目分析:HDU - 3397 的弱化版

简化版题意就是,初始时有一个全 0 的序列,操作 1 是将区间内的数全部修改为 1,操作 2 是将区间内的数全部修改为 0,操作 3 是将区间内的数全部置反,即 0 变为 1,1 变为 0,每次询问需要回答从左侧开始首次出现的 0 的位置,三个操作其实就是一个比较基础的 lazy 序的实现,一个控制区间覆盖,一个控制区间翻转,而对于每次询问只需要在线段树上行整体二分就可以轻松得到答案了

需要注意的是因为区间范围非常的大,所以需要离线去做,先将区间离散化一下,因为对于某段操作 [ l , r ] 来说,只会影响到 l - 1 和 r + 1 ,所以离散化的时候多离散化几个点就好了

代码:
 

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
     
typedef long long LL;
     
typedef unsigned long long ull;
     
const int inf=0x3f3f3f3f;

const int N=1e6+100;

vector<LL>node;

int n;

struct qu
{
	int op;
	LL l,r;
	void input()
	{
		scanf("%d%lld%lld",&op,&l,&r);
		node.push_back(l);
		node.push_back(r);
		node.push_back(max(1LL,l-1));
		node.push_back(max(1LL,r-1));
		node.push_back(l+1);
		node.push_back(r+1);
	}
}q[N];

void discreate()
{
	node.push_back(1);
	sort(node.begin(),node.end());
	node.erase(unique(node.begin(),node.end()),node.end());
	for(int i=1;i<=n;i++)
	{
		q[i].l=lower_bound(node.begin(),node.end(),q[i].l)-node.begin();
		q[i].r=lower_bound(node.begin(),node.end(),q[i].r)-node.begin();
	}
}

struct Node
{
	int l,r,len,sum,lazy1,lazy2;
}tree[N<<2];

void pushup(int k)
{
	tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}

void pushdown(int k)
{
	if(tree[k].lazy1!=-1)
	{
		tree[k<<1].lazy2=tree[k<<1|1].lazy2=0;
		int lz=tree[k].lazy1;
		tree[k].lazy1=-1;
		tree[k<<1].lazy1=tree[k<<1|1].lazy1=lz;
		tree[k<<1].sum=tree[k<<1].len*lz;
		tree[k<<1|1].sum=tree[k<<1|1].len*lz;
	}
	if(tree[k].lazy2)
	{
		int lz=tree[k].lazy2;
		tree[k].lazy2=0;
		tree[k<<1].lazy2^=1;
		tree[k<<1|1].lazy2^=1;
		tree[k<<1].sum=tree[k<<1].len-tree[k<<1].sum;
		tree[k<<1|1].sum=tree[k<<1|1].len-tree[k<<1|1].sum;
	}
}

void build(int k,int l,int r)
{
	tree[k].l=l;
	tree[k].r=r;
	tree[k].len=r-l+1;
	tree[k].lazy1=-1;
	tree[k].lazy2=0;
	tree[k].sum=0;
	if(l==r)
		return;
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
}

void update(int k,int l,int r,int op)//op=1,2,3
{
	if(tree[k].l>r||tree[k].r<l)
		return;
	if(tree[k].l>=l&&tree[k].r<=r)
	{
		if(op==1)
		{
			tree[k].sum=tree[k].len;
			tree[k].lazy1=1;
			tree[k].lazy2=0;
		}
		else if(op==2)
		{
			tree[k].sum=0;
			tree[k].lazy1=0;
			tree[k].lazy2=0;
		}
		else if(op==3)
		{
			tree[k].sum=tree[k].len-tree[k].sum;
			tree[k].lazy2^=1;
		}
		return;
	}
	pushdown(k);
	update(k<<1,l,r,op);
	update(k<<1|1,l,r,op);
	pushup(k);
}

int query(int k)
{
	if(tree[k].l==tree[k].r)
		return tree[k].l;
	pushdown(k);
	if(tree[k<<1].sum!=tree[k<<1].len)
		return query(k<<1);
	else
		return query(k<<1|1);
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		q[i].input();
	discreate();
	build(1,0,node.size()-1);
	for(int i=1;i<=n;i++)
	{
		update(1,q[i].l,q[i].r,q[i].op);
		printf("%lld\n",node[query(1)]);
	}









    return 0;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Frozen_Guardian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值