题目描述:
给你一个无限长的数组,初始的时候都为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;
}