CF817F MEX Queries
题意
- 维护一个 序列 ,初始均为 。
- 有 组询问,每组询问输入三个数 :
- :把 赋值为 。
- :把 赋值为 。
- :把 取反。
- 每次操作后输出一个数 ,满足 且 最小。
分析
看到区间操作,显然第一时间可以想到线段树,对于 的操作,维护一个标记 ,表示 和 表示把该区间复制为 , 表示没有标记,对于 的操作,维护一个标记 表示是否有翻转。
然而题目求的是总体的 ,我们要找到最小的值为 的位置,于是就可以维护一个值 表示该区间是否全为 ,查询答案是从根节点往下找,如果左子树全为 那么答案就在右子树,否则在左子树。
然而这样并不好维护,经过翻转操作后无法确定 的值,你不知道翻转前该区间是全为 还是有一点 ,因此我们可以再维护一个值 表示区间中是否至少有一个 ,这样翻转某个区间的函数就很好写了:
void rev(int p){//翻转p节点
a[p].tag2^=1;//翻转标记
if(a[p].full)
a[p].full=a[p].any=0;//之前全是1,翻转后全是0
else{
a[p].full=!a[p].any;//之前没有满,翻转后的结果随any取值而定
a[p].any=1;//由于翻转前没有满,所以翻转后一定有1
}
}
赋值时,把 和 都改成赋的值就好了。
void fuz(int p,int v){//赋值
a[p].any=a[p].full=a[p].tag1=v;
a[p].tag2=0;//赋值后无所谓翻转
}
相应的 :
void pushup(int p){
a[p].full=a[pl].full&&a[pr].full;
a[p].any=a[pl].any||a[pr].any;
}
由于 范围过大,我一开始使用的是动态开点的线段树,然而由于树太深,开点操作太多导致 TLE 了,于是又加上了离散化才过,可动态开点加上离散化后就没太大用处了。
关于离散化的提示:一定要有 !定要有 !要有 !有 !!!(手动回声
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=5e5+10;
#define pl a[p].tl
#define pr a[p].tr
#define DOP_S_T_T bool
struct DOP_Segment_Tree{
int root,tot;
struct Tree{
ll l,r;
int tl,tr;//左右子树
int tag1,tag2;
DOP_S_T_T full,any;
}a[N*4];
void fuz(int p,int v){//赋值
a[p].any=a[p].full=a[p].tag1=v;
a[p].tag2=0;//赋值后无所谓翻转
}
void rev(int p){//翻转p节点
a[p].tag2^=1;//翻转标记
if(a[p].full)
a[p].full=a[p].any=0;//之前全是1,翻转后全是0
else{
a[p].full=!a[p].any;//之前没有满,翻转后的结果随any取值而定
a[p].any=1;//由于翻转前没有满,所以翻转后一定有1
}
}
void pushup(int p){
a[p].full=a[pl].full&&a[pr].full;
a[p].any=a[pl].any||a[pr].any;
}
void pushdown(int p){
if(a[p].tag1!=-1){
fuz(pl,a[p].tag1);
fuz(pr,a[p].tag1);
a[p].tag1=-1;
}
else if(a[p].tag2){
if(a[pl].tag1==-1)
rev(pl);
else
fuz(pl,!a[pl].tag1);
if(a[pr].tag1==-1)
rev(pr);
else
fuz(pr,!a[pr].tag1);
a[p].tag2=0;
}
}
void make(int p){//开点
if(!pl){
ll mid=(a[p].l+a[p].r)>>1;
a[pl=++tot].l=a[p].l;
a[pl].r=mid;
fuz(pl,0);
a[pr=++tot].l=mid+1;
a[pr].r=a[p].r;
fuz(pr,0);
}
}
void build(ll l,ll r){//建树
root=tot=1;
a[root].l=l;
a[root].r=r;
fuz(root,0);
}
void change1(int p,ll l,ll r,DOP_S_T_T v){//赋值
if(l<=a[p].l&&a[p].r<=r){
fuz(p,v);
return;
}
make(p);
pushdown(p);
ll mid=(a[p].l+a[p].r)>>1;
if(l<=mid)
change1(pl,l,r,v);
if(r>mid)
change1(pr,l,r,v);
pushup(p);
}
void change2(int p,ll l,ll r){//翻转
if(l<=a[p].l&&a[p].r<=r){
if(a[p].tag1!=-1) fuz(p,!a[p].tag1);
else rev(p);
return;
}
make(p);
pushdown(p);
ll mid=(a[p].l+a[p].r)>>1;
if(l<=mid)
change2(pl,l,r);
if(r>mid)
change2(pr,l,r);
pushup(p);
}
ll ask(int p){//查询
if(a[p].l==a[p].r)
return a[p].l;
make(p);
pushdown(p);
if(a[pl].full)
return ask(pr);
return ask(pl);
}
}tree;
int n,m;
ll t[N],l[N],r[N],a[4*N];
int main(){
n=read();
a[++m]=1;
for(int i=1;i<=n;i++){
t[i]=read();l[i]=read();r[i]=read();
a[++m]=max(l[i]-1,1ll);a[++m]=l[i];
a[++m]=r[i];a[++m]=r[i]+1;
}
sort(a+1,a+m+1);
int tot=unique(a+1,a+m+1)-(a+1);
tree.build(1,tot+10);
for(int i=1;i<=n;i++){
l[i]=lower_bound(a+1,a+tot+1,l[i])-a;
r[i]=lower_bound(a+1,a+tot+1,r[i])-a;
if(t[i]==1) tree.change1(1,l[i],r[i],1);
if(t[i]==2) tree.change1(1,l[i],r[i],0);
if(t[i]==3) tree.change2(1,l[i],r[i]);
write(a[tree.ask(1)]);
putchar('\n');
}
return 0;
}

浙公网安备 33010602011771号