mex(线段树+离散化)
Posted harrypotter-fan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
以上是关于mex(线段树+离散化)的主要内容,如果未能解决你的问题,请参考以下文章