线段树之区间合并
之前多校整过一道,整了两天才弄懂= =……现在整了半个上午……而且还严重参考了大牛代码= =
以后还得再做一次,经典题目多做有益身心╮(╯▽╰)╭
贴代码:(和大牛代码基本一样= =,只是变量名字不同)
#include <iostream>
#include <cstdio>
#include <cstring>
#define lson l,mid,dex<<1 /************************注意在下的宏定义......免得楼下出现神奇变量看不懂....*********/
#define rson mid+1,r,dex<<1|1
#define havemid int mid = (l+r)>>1
#define left (dex<<1)
#define right (dex<<1|1)
using namespace std;
const int maxx = 51000;
int tage[maxx<<2];//延迟标志,有3个值,-1表示无需更新,1表示有人入住需要把空房间数清零,0表示有人离开,需要把空房间数堆满
int rooml[maxx<<2];//该区间左端开始的空房间数目
int roomr[maxx<<2];//该区间右端开始的空房间数目
int roommid[maxx<<2];//该区间里最长的连续空房间的数目
void Push_down(int dex,int x)
{
if(tage[dex]!=-1)
{
tage[dex<<1] = tage[dex<<1|1] = tage[dex];//延迟标志向下传递,不解释
rooml[right] = roomr[right] = roommid[right] = tage[dex]?0:(x>>1);//如果延迟标志为0,则将区间内空房间数清零(详见楼上注解)
rooml[left] = roomr[left] = roommid[left] = tage[dex]?0:(x-(x>>1));//如果延迟标志为1,则将区间内空房间数堆满
tage[dex] = -1;//表示本区间已经更新
}
}
void Push_up(int dex,int x)
{
rooml[dex] = rooml[left];//无论左端开始数的空房间数是否充满整个空间(即即使要加上右儿子从左端开始数的空房间数),都要先把左儿子的房间数复制给父亲的rooml
roomr[dex] = roomr[right];//同上
if(rooml[left] == (x-(x>>1))) rooml[dex]+=rooml[right];//如果左儿子的rooml充满区间,则加上右儿子的rooml
if(roomr[right] == (x>>1)) roomr[dex]+=roomr[left];//如果右儿子的roomr充满区间,则加上左儿子的roomr
roommid[dex] = max(roomr[left] + rooml[right],max(roommid[left], roommid[right]));//roomr[left] + rooml[right]表示合并区间时产生的连续不断的空房间数
}
void build(int l,int r,int dex)//不解释= =
{
tage[dex] = -1;
rooml[dex] = roomr[dex] = roommid[dex] = r-l+1;
if(l==r) return;
havemid;//宏定义
build(lson);//宏定义+1
build(rson);//宏定义+2
}
void updata(int L,int R,int mode, int l,int r,int dex)
{
if(L<=l && R>=r)//如果目前区间为搜索区间的子区间,则子区间被完全覆盖
{
rooml[dex] = roomr[dex] = roommid[dex] = mode?0:r-l+1;//根据延迟标志选择性更新
tage[dex] = mode;
return ;
}
Push_down(dex, r-l+1);//在楼下需要用到儿子节点的语句之前,先行一步向下更新(还没更新的)儿子节点
havemid;
if(L<=mid) updata(L,R,mode,lson);//如果左儿子还有没更新的就更新
if(R>mid) updata(L,R,mode,rson);//略同上
Push_up(dex,r-l+1);//合并区间
}
int query(int x,int l,int r,int dex)
{
if(l==r) return l;//搜到子节点则返回 (经测试,返回0竟然也没问题= =,估计数据不怎么样?)
Push_down(dex,r-l+1);//更新未更新的儿子节点
havemid;
if(roommid[left] >= x) return query(x,lson);//一直找左儿子的最大连续空房间,一直找到左儿子的roommid不满足,则这个区间一定落在中间的区间,否则在右区间
else if(rooml[dex<<1|1]+roomr[dex<<1]>=x) return mid - roomr[dex<<1]+1;
else return query(x,rson);
}
int main()//不解释
{
// freopen("123.txt","r",stdin);
int n,m;
while(~scanf("%d %d",&n,&m))
{
build(1,n,1);
for(int i=1; i<=m; i++)
{
int a;
scanf("%d",&a);
if(a==1)
{
int b;
scanf("%d",&b);
if(roommid[1]<b) puts("0");
else
{
int ans = query(b,1,n,1);
printf("%d\n",ans);
updata(ans,ans+b-1,1,1,n,1);
}
}
else
{
int u,v;
scanf("%d %d",&u,&v);
updata(u,u+v-1,0,1,n,1);
}
}
}
return 0;
}