Codeforces 817F. MEX Queries
题目
给你一个无限长的数组,初始的时候都为0,有3种操作:
操作1是把给定区间[l,r]设为1。
操作2是把给定区间[l,r]设为0。
操作3把给定区间[l,r]的0,1反转。
l,r<=1018
一共n(n<=105)个操作,每次操作后要输出最小位置的0。
解法
看到维护区间,想到线段树。
看到数据范围,想到把操作离线然后离散化。
然后再yy一下合并状态:
每个节点维护两个信息:
min0表示该区间最小位置的0,初始值为l (当时错在了这里)。
min1表示该区间最小位置的1,初始值为inf。
合并时左右取最小即可
操作
- min0=inf,min1=l
- min0=l,min1=inf
- 交换min0,min1
通过懒标记维护。
一些细节问题
- 离散化时要把r+1也一同离散化,否则 (r0,l1)这段区间会遗失。(当时错在了这里*2)
- pushdown的时候可能同时会有反转和修改操作,为了防止顺序出错,要做点处理(当时错在了这里*3)
- 反转标记在前,修改操作在后:可以直接无视掉反转标记。所以要在打标记前清除反转标记。
- 反转标记在后,修改操作在前:必须先处理修改操作。所以pushdown函数里修改要写在反转的前面
- 数组要开n*3*4(每个操作最多有三个数,线段树空间要*4)(当时错在了这里*4)
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
#define N 5000000
#define int long long
#define root 1,1,maxn
#define mid (l+r)/2
#define ls id*2
#define rs id*2+1
#define lc ls,l,mid,tl,tr
#define rc rs,mid+1,r,tl,tr
#define inf 4611686018427387904
int min0[N],min1[N],dic[N],tag[N],maxn,neg[N];
struct opt
{
int type,l,r;
}opts[N];
map<int,int> m;
void pushdown(int id,int l,int r)
{
if(tag[id])
{
tag[ls]=tag[rs]=tag[id];
neg[ls]=neg[rs]=0;
if(tag[id]-1>0) min0[ls]=min0[rs]=inf,min1[ls]=l,min1[rs]=mid+1;
else min0[ls]=l,min0[rs]=mid+1,min1[ls]=min1[rs]=inf;
}
if(neg[id])
{
//if(tag[ls]||tag[rs]) throw 'a';
neg[ls]=!neg[ls],neg[rs]=!neg[rs];
swap(min0[ls],min1[ls]);
swap(min0[rs],min1[rs]);
}
neg[id]=tag[id]=0;
}
void update(int id)
{
min0[id]=min(min0[ls],min0[rs]);
min1[id]=min(min1[ls],min1[rs]);
}
void set(int id,int l,int r,int tl,int tr,int v)
{
if(l>=tl&&r<=tr)
{
if(v) min0[id]=inf,min1[id]=l;
else min0[id]=l,min1[id]=inf;
tag[id]=v+1;
neg[id]=0;
return;
}
pushdown(id,l,r);
if(tl<=mid) set(lc,v);
if(tr>mid) set(rc,v);
update(id);
}
void set2(int id,int l,int r,int tl,int tr)
{
if(l>=tl&&r<=tr)
{
swap(min0[id],min1[id]);
neg[id]=!neg[id];
return;
}
pushdown(id,l,r);
if(tl<=mid) set2(lc);
if(tr>mid) set2(rc);
update(id);
}
void build(int id,int l,int r)
{
min0[id]=l;
min1[id]=inf;
if(l==r) return;
build(ls,l,mid);
build(rs,mid+1,r);
}
signed main()
{
int n,cnt=0;
//freopen("data.in","r",stdin);
//freopen("my.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&opts[i].type,&opts[i].l,&opts[i].r);
if(!opts[i].l||!opts[i].r) throw "a";
m[opts[i].l]=1;
m[opts[i].r]=1;
m[opts[i].r+1]=1;
}
m[1]=1;
for(map<int,int>::iterator it=m.begin();it!=m.end();it++)//通过map离散化
{
dic[++cnt]=(*it).first;
(*it).second=cnt;
}
maxn=m.size();
build(root);
for(int i=1;i<=n;i++)
{
if(opts[i].type<=2) set(root,m[opts[i].l],m[opts[i].r],opts[i].type==1);
else set2(root,m[opts[i].l],m[opts[i].r]);
printf("%lld\n",dic[min0[1]]);
}
}
看都看了,顺手点个推荐呗 :)

浙公网安备 33010602011771号