mex(线段树+离散化)
题目描述:
给你一个无限长的数组,初始的时候都为0,有3种操作:
操作1是把给定区间[l,r][l,r] 设为1,
操作2是把给定区间[l,r][l,r] 设为0,
操作3把给定区间[l,r][l,r] 0,1反转。
一共n个操作,每次操作后要输出最小位置的0。
题解:
经过分析观察,可以发现,答案只有可能是1,l,r+1
所以我们开一个数组记录1,以及所有的l,r,r+1,并离散化
然后用线段树模拟操作即可
这里有两种思路:
一种是记录某一区间内0的最小位置和1的最小位置,反转时互换两个位置
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=1e5+5; const int maxn=3e5+5; int n,m;ll a[maxn]; struct que{ int op;ll l,r; }q[N]; int s0[maxn<<2],s1[maxn<<2],lazy[maxn<<2],rev[maxn<<2]; void pushup(int u){ if(s0[u*2]) s0[u]=s0[u*2]; else if(s0[u*2+1]) s0[u]=s0[u*2+1]; else s0[u]=0; if(s1[u*2]) s1[u]=s1[u*2]; else if(s1[u*2+1]) s1[u]=s1[u*2+1]; else s1[u]=0; } void build(int u,int l,int r){ rev[u]=0;lazy[u]=-1; if(l==r){ s0[u]=l;s1[u]=0; return; } int mid=(l+r)/2; build(u*2,l,mid); build(u*2+1,mid+1,r); pushup(u); } void pushdown(int u,int l,int r){ if(lazy[u]!=-1){ lazy[u*2]=lazy[u]; lazy[u*2+1]=lazy[u]; rev[u*2]=rev[u*2+1]=0; int mid=(l+r)/2; if(lazy[u]==1){ s0[u*2]=s0[u*2+1]=0; s1[u*2]=l,s1[u*2+1]=mid+1; } else if(lazy[u]==0){ s0[u*2]=l,s0[u*2+1]=mid+1; s1[u*2]=s1[u*2+1]=0; } lazy[u]=-1; } if(rev[u]){ if(lazy[u*2]!=-1) lazy[u*2]^=1; else rev[u*2]^=1; if(lazy[u*2+1]!=-1) lazy[u*2+1]^=1; else rev[u*2+1]^=1; swap(s0[u*2],s1[u*2]); swap(s0[u*2+1],s1[u*2+1]); rev[u]=0; } } void update(int u,int l,int r,int a,int b,int k){ if(a<=l&&b>=r){ lazy[u]=k; rev[u]=0; if(k==1) s0[u]=0,s1[u]=l; else if(k==0) s0[u]=l,s1[u]=0; return; } pushdown(u,l,r); int mid=(l+r)/2; if(a<=mid) update(u*2,l,mid,a,b,k); if(b>mid) update(u*2+1,mid+1,r,a,b,k); pushup(u); } void revere(int u,int l,int r,int a,int b){ if(a<=l&&b>=r){ if(lazy[u]==-1) rev[u]^=1; else lazy[u]^=1; swap(s0[u],s1[u]); return; } pushdown(u,l,r); int mid=(l+r)/2; if(a<=mid) revere(u*2,l,mid,a,b); if(b>mid) revere(u*2+1,mid+1,r,a,b); pushup(u); } int main(){ scanf("%d",&m); a[++n]=1; for(int i=1;i<=m;i++){ scanf("%d%lld%lld",&q[i].op,&q[i].l,&q[i].r); a[++n]=q[i].l;a[++n]=q[i].r;a[++n]=q[i].r+1; } sort(a+1,a+n+1); n=unique(a+1,a+1+n)-a-1; build(1,1,n); for(int i=1;i<=m;i++){ if(q[i].op==1){ int x=lower_bound(a+1,a+1+n,q[i].l)-a; int y=lower_bound(a+1,a+1+n,q[i].r)-a; update(1,1,n,x,y,1); } else if(q[i].op==2){ int x=lower_bound(a+1,a+1+n,q[i].l)-a; int y=lower_bound(a+1,a+1+n,q[i].r)-a; update(1,1,n,x,y,0); } else{ int x=lower_bound(a+1,a+1+n,q[i].l)-a; int y=lower_bound(a+1,a+1+n,q[i].r)-a; revere(1,1,n,x,y); } if(!s0[1]) printf("%lld\n",a[n]+1); else printf("%lld\n",a[s0[1]]); } return 0; }
另一种是记录某一区间内1的个数,查询时如果一个区间内1的个数小于这个区间的总个数,则说明这个区间内有0,递归下去
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=1e5+5; const int maxn=3e5+5; int n,m;ll a[maxn]; struct que{ int op;ll l,r; }q[N]; int sum[maxn<<2],lazy[maxn<<2],rev[maxn<<2]; void build(int u,int l,int r){ rev[u]=0;lazy[u]=-1;sum[u]=0;//错误1:一开始只在l==r时赋了初值 if(l==r) return; int mid=(l+r)/2; build(u*2,l,mid); build(u*2+1,mid+1,r); sum[u]=sum[u*2]+sum[u*2+1]; } void pushdown(int u,int l,int r){ int mid=(l+r)>>1; if(lazy[u]!=-1){ lazy[u<<1]=lazy[u]; lazy[u<<1|1]=lazy[u]; rev[u<<1]=0; rev[u<<1|1]=0; if(lazy[u]==1){ sum[u<<1]=mid-l+1; sum[u<<1|1]=r-mid; } else{ sum[u<<1]=0; sum[u<<1|1]=0; } lazy[u]=-1; } if(rev[u]){ if(lazy[u<<1]!=-1) lazy[u<<1]^=1; else rev[u<<1]^=1; if(lazy[u<<1|1]!=-1) lazy[u<<1|1]^=1; else rev[u<<1|1]^=1; sum[u<<1]=mid-l+1-sum[u<<1]; sum[u<<1|1]=r-mid-sum[u<<1|1]; rev[u]=0; } //还是错误2 } void update(int u,int l,int r,int a,int b,int p){ if(a<=l&&b>=r){ if(l==r){ if(p==1) sum[u]=1; else if(p==2) sum[u]=0; else sum[u]^=1; } else{ if(p==1){ lazy[u]=1; rev[u]=0; sum[u]=r-l+1; } else if(p==2){ lazy[u]=0; rev[u]=0; sum[u]=0; } else{ if(lazy[u]==-1) rev[u]^=1; else lazy[u]^=1; sum[u]=r-l+1-sum[u]; } //错误2:lazy,rev是会相互影响的 } return; } pushdown(u,l,r); int mid=(l+r)/2; if(a<=mid) update(u*2,l,mid,a,b,p); if(b>mid) update(u*2+1,mid+1,r,a,b,p); sum[u]=sum[u*2]+sum[u*2+1]; } ll query(int u,int l,int r){ if(l==r) return a[l]; pushdown(u,l,r); int mid=(l+r)>>1; if(sum[u<<1]<mid-l+1) return query(u<<1,l,mid); else return query(u<<1|1,mid+1,r); } int main(){ scanf("%d",&m); a[++n]=1; for(int i=1;i<=m;i++){ scanf("%d%lld%lld",&q[i].op,&q[i].l,&q[i].r); a[++n]=q[i].l;a[++n]=q[i].r;a[++n]=q[i].r+1; } sort(a+1,a+n+1); n=unique(a+1,a+1+n)-a-1; build(1,1,n); for(int i=1;i<=m;i++){ int x=lower_bound(a+1,a+1+n,q[i].l)-a; int y=lower_bound(a+1,a+1+n,q[i].r)-a; update(1,1,n,x,y,q[i].op); printf("%lld\n",query(1,1,n)); } return 0; }