线段树维护区间内容的一道经典题,值得一做,废话少说,开始讲解吧。
1.线段树维护内容
线段树维护一个最长区间。
线段树节点维护4个东西:
1.必须从左节点延伸的最长长度(lm)
2.必须从右节点延伸的最长长度(rm)
3.这一段的最长未占用长度(mm)
5.一个lazy标记,用于线段树的yy (laz = 0/1/2 <不需下放/需下放住房/需下放退房>)
2.区间内容的合并
对于左右儿子的合并(fa = lc+rc)
1.如果lc左侧全是空房,那么fa.lm为lc.sum+rc.lm ;
2.如果不是全为空房,那么fa.lm = lc.lm ;
3.对于fa.rm,右侧最大延展,类似于左侧延展。
4.对于区间最大延伸,fa.mm = max( max(fa.lm,fa.rm) , (lc.rm+rc.lm) , max(lc.mm,rc.mm)) ;
3.信息修改的处理
对于修改(住房及退房)<[target left , target right]>
一.住房:
1.完全包含状况(tl<=l && r<=tr),区间的lm、rm、mm、sum全部变为0 ; laz = 1;
2.不完全包含情况递归处理左右子树
二.退房:
1.完全包含状况(tl<=l && r<=tr),区间的lm、rm、mm、sum全部变为(l-r+1) ; laz = 2;
2.不完全包含情况递归处理左右子树
三.pushdown_lazy的操作
1.在处理节点之前进行。
2.将fa.laz恢复为0。
3.对于laz == 1\2 的情况,同住房\退房的方法处理
4.查询答案的方法
对于询问、查询<[target left , target right], target length == K >
1.查询左儿子lc.mm是否大于K
-大于等于K:递归左儿子查找位置,返回。
-小于K,进入下一步
2.判断lc.rm + rc.lm 是否大于K
-大于等于K:直接返回(midpos - lc.rm + 1)的左端点位置
-小于K,进入下一步
3.判断右儿子rc.mm是否大于K
-大于等于L:递归右儿子查找位置,返回。
-小于K:直接返回,输出无解(0)
5.具体实现代码:
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define lc ro<<1
#define rc ro<<1|1
#define ll long long
#define maxn 50010
using namespace std;
inline int gi()
{
int date = 0,m = 1; char ch = 0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch = getchar();
if(ch=='-'){m = -1; ch = getchar();}
while(ch>='0' && ch<='9')
{
date = date*10+ch-'0';
ch = getchar();
}return date*m;
}
inline void write(int ac)
{
if(ac>9)write(ac/10);
putchar(ac%10+'0');
}
struct segment_tree{int lm,rm,mm,laz;};
segment_tree t[maxn<<3+5];
int flag,pos,L,R,len,order;
void merge_item(int ro,int l,int r)
{
int mid = (l+r)>>1;
if(t[lc].mm == (mid-l+1))t[ro].lm = t[lc].mm+t[rc].lm;
else t[ro].lm = t[lc].lm;
if(t[rc].mm == (r-mid))t[ro].rm = t[rc].mm+t[lc].rm;
else t[ro].rm = t[rc].rm;
int mlc = max( t[lc].mm , t[rc].mm );
mlc = max( mlc , max( t[ro].lm , t[ro].rm ) );
t[ro].mm = max( mlc , t[lc].rm + t[rc].lm);
}
void pushdown(int ro,int l,int r)
{
if(t[ro].laz == 1)
{
t[lc].lm = t[rc].lm = t[lc].rm = t[rc].rm = 0;
t[lc].mm = t[rc].mm = 0;
t[lc].laz = t[rc].laz = 1;
}
else if(t[ro].laz == 2)
{
int mid = (l+r)>>1;
t[lc].lm = t[lc].rm = t[lc].mm = mid-l+1;
t[rc].lm = t[rc].rm = t[rc].mm = r-mid;
t[lc].laz = t[rc].laz = 2;
}
t[ro].laz = 0; return;
}
void build(int ro,int l,int r)
{
if(l == r){
t[ro].lm = t[ro].rm = t[ro].mm = 1;
t[ro].laz = 0; return;
}
int mid = (l+r)>>1;
build(lc,l,mid); build(rc,mid+1,r);
merge_item(ro,l,r); return;
}
void query(int ro,int l,int r,int tlen)
{
if(t[ro].laz)pushdown(ro,l,r);
if(l == r){flag = 1; pos = l; return;}
int mid = (l+r)>>1;
if(t[lc].mm >= tlen)
query(lc,l,mid,tlen);
else if(t[lc].rm + t[rc].lm >= tlen && !flag)
{flag = 1; pos = mid - t[lc].rm + 1; return;}
else if(t[rc].mm>=tlen && !flag)
query(rc,mid+1,r,tlen);
merge_item(ro,l,r);
}
void update(int ro,int l,int r,int tl,int tr,int ord)
{
if(t[ro].laz)pushdown(ro,l,r);
if(tl>r || tr<l)return;
if(tl<=l && r<=tr)
{
if(ord == 1){
t[ro].lm = t[ro].rm = t[ro].mm = 0;
t[ro].laz = 1; return;
}
else if(ord == 2){
t[ro].lm = t[ro].rm = t[ro].mm = r-l+1;
t[ro].laz = 2; return;
}
}
int mid = (l+r)>>1;
update(lc,l,mid,tl,tr,ord);
update(rc,mid+1,r,tl,tr,ord);
merge_item(ro,l,r); return;
}
/*
void recheck(int ro,int l,int r)
{
if(t[ro].laz)pushdown(ro,l,r);
if(l == r){write(t[ro].mm);putchar(' ');return;}
int mid = (l+r)>>1;
recheck(lc,l,mid);
recheck(rc,mid+1,r);
return;
}
*/
int main()
{
freopen("Hotel.in","r",stdin);
int n = gi(),m = gi();
build(1,1,n);
while(m -- )
{
order = gi();
if(order == 1)
{
flag = 0; pos = 0;
len = gi();
query(1,1,n,len);
write(pos); putchar('\n');
//recheck(1,1,n); cout<<endl; //检查函数
if(pos)update(1,1,n,pos,pos+len-1,1);
//recheck(1,1,n); cout<<endl;
}
else if(order == 2)
{
L = gi(); R = L + gi() - 1;
update(1,1,n,L,R,2);
}
}return 0;
}
Hahahahaha!