题目大意
一段01序列,0代表没人住,1代表有人住,住房和退房都要求是修改一段连续区间.
求能够安排住房的区间的左端点
题解
线段树
要判断能否住 要维护区间0序列长最大值.和区间0序列最左边的长度和右边长度
代码
#include<cstdio> #include<algorithm> #include<iostream> using namespace std; int sum[400010],lm[400010],rm[400010],m[400010],tag[400010],n,T; void pushup(int rt){ if(m[rt<<1]==sum[rt<<1]){ lm[rt]=m[rt<<1]+lm[rt<<1|1]; }else{ lm[rt]=lm[rt<<1]; } if(m[rt<<1|1]==sum[rt<<1|1]){ rm[rt]=m[rt<<1|1]+rm[rt<<1]; }else{ rm[rt]=rm[rt<<1|1]; } m[rt]=max(max(m[rt<<1],m[rt<<1|1]),rm[rt<<1]+lm[rt<<1|1]); return; } void pushdown(int rt){ if(tag[rt]==0) return; if(tag[rt]==1){ tag[rt<<1]=tag[rt<<1|1]=1; m[rt<<1]=lm[rt<<1]=rm[rt<<1]=0; m[rt<<1|1]=lm[rt<<1|1]=rm[rt<<1|1]=0; } if(tag[rt]==2){ tag[rt<<1]=tag[rt<<1|1]=2; m[rt<<1]=lm[rt<<1]=rm[rt<<1]=sum[rt<<1]; m[rt<<1|1]=lm[rt<<1|1]=rm[rt<<1|1]=sum[rt<<1|1]; } tag[rt]=0; } void build(int rt,int l,int r){ lm[rt]=rm[rt]=m[rt]=sum[rt]=r-l+1; tag[rt]=0; if(l==r) return; int mid=(l+r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); return; } int query(int rt,int l,int r,int len){ pushdown(rt); if(l==r) return l; int mid=(l+r)>>1; if(m[rt<<1]>=len) return query(rt<<1,l,mid,len); if(rm[rt<<1]+lm[rt<<1|1]>=len) return mid-rm[rt<<1]+1; else return query(rt<<1|1,mid+1,r,len); } void modify(int L,int R,int c,int rt,int l,int r){ pushdown(rt); if((L<=l)&&(r<=R)){ if(c==1) m[rt]=lm[rt]=rm[rt]=0; else m[rt]=lm[rt]=rm[rt]=sum[rt]; tag[rt]=c; return; } int mid=(l+r)>>1; if(L<=mid) modify(L,R,c,rt<<1,l,mid); if(R>mid) modify(L,R,c,rt<<1|1,mid+1,r); pushup(rt); } int main(){ scanf("%d%d",&n,&T); build(1,1,n); while(T--){ int opt,a,b; scanf("%d",&opt); if(opt==1){ scanf("%d",&a); if(m[1]<a){printf("0\n");continue;} int p=query(1,1,n,a); printf("%d\n",p); modify(p,p+a-1,1,1,1,n); }else{ scanf("%d%d",&a,&b); modify(a,a+b-1,2,1,1,n); } } return 0; }