心得:线段树主要需要思考的是
1.维护什么:每一个节点需要维护的东西
2.pushUp:两个小区间合并成大区间的方法合理性
3.pushDown:lazy向下传递,以及节点的各属性更新
4.query:花式query
题意:n间房子 ,操作1:问你能否找出连续的x个房子, 如果能输出最左边的房间编号,并入住。操作2:让连续的区间住户退房。
思路:线段树节点维护 最大连续空闲区间长度mx,最左边的连续空闲区间长度lto,最右边的连续空闲区间长度rto,整个区间是否是空的a,以及lazy。
pushUp:考虑左边右边以及连接处。
pushDown:lz标记为-1代表不需要操作,0代表让所有房价退房,1代表入住,然后向下更新小区间信息。
一个线段树就是一下午
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define PII pair<int,int>
#define MP make_pair
const LL mod = 1e9+7;
const int MX = 4e5+5;
int lto[MX],rto[MX],mx[MX],a[MX],lz[MX];//a标记这一段有满或空,lz标记(-1初始化
inline void pushUp(int rt){
lto[rt]=lto[rt<<1];
if(a[rt<<1]==0) lto[rt]+=lto[rt<<1|1];
rto[rt]=rto[rt<<1|1];
if(a[rt<<1|1]==0) rto[rt]+=rto[rt<<1];
mx[rt]=max(lto[rt<<1|1]+rto[rt<<1],max(mx[rt<<1],mx[rt<<1|1]));
a[rt]=1;
if(a[rt<<1]==0&&a[rt<<1|1]==0) a[rt]=0;
}
inline void pushDown(int rt,int le){
if(lz[rt]==-1)return ;
if(lz[rt]==1){
mx[rt]=0,mx[rt<<1]=0,mx[rt<<1|1]=0;
lto[rt]=0,lto[rt<<1]=0,lto[rt<<1|1]=0;
rto[rt]=0,rto[rt<<1]=0,rto[rt<<1|1]=0;
a[rt]=1,a[rt<<1]=1,a[rt<<1|1]=1;
}
if(lz[rt]==0){
mx[rt]=le,mx[rt<<1]=le-(le>>1),mx[rt<<1|1]=le>>1;
lto[rt]=le,lto[rt<<1]=le-(le>>1),lto[rt<<1|1]=le>>1;
rto[rt]=le,rto[rt<<1]=le-(le>>1),rto[rt<<1|1]=le>>1;
a[rt]=0,a[rt<<1]=0,a[rt<<1|1]=0;
}
lz[rt<<1]=lz[rt<<1|1]=lz[rt];
lz[rt]=-1;
}
void build(int l,int r,int rt){
lz[rt]=-1;
if(l==r){
lto[rt]=rto[rt]=mx[rt]=1;a[rt]=0;
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushUp(rt);
}
void update(int L,int R,int c,int l,int r,int rt){
if(l>=L&&r<=R){
lz[rt]=c;
mx[rt]=lto[rt]=rto[rt]=(c^1)*(r-l+1);
a[rt]=c;
return ;
}
pushDown(rt,r-l+1);
int m=(l+r)>>1;
if(m>=L) update(L,R,c,l,m,rt<<1);
if(m<R) update(L,R,c,m+1,r,rt<<1|1);
pushUp(rt);
}
int query(int k,int l,int r,int rt){ //k个连续
if(l==r) {
if(mx[rt]<k) return 0;
return l;
}
pushDown(rt,r-l+1);
int m=(l+r)>>1;
if(mx[rt<<1]>=k) return query(k,l,m,rt<<1);
if(rto[rt<<1]+lto[rt<<1|1]>=k) return m-rto[rt<<1]+1;
return query(k,m+1,r,rt<<1|1);
}
int main(){
int n,m;cin>>n>>m;
build(1,n,1);
while(m--){
int op;scanf("%d",&op);
if(op==1){
int x;scanf("%d",&x);
int l=query(x,1,n,1);
printf("%d\n",l);
if(l==0)continue;
update(l,l+x-1,1,1,n,1);
}
else {
int l,x;scanf("%d%d",&l,&x);
update(l,l+x-1,0,1,n,1);
}
}
return 0;
}
/*
10 9
1 3
1 3
1 4
1 1*/