传送门:牛客
题目描述:
参考样例,第一行输入n,m ,n代表有n个房间,编号为1---n,开始都为空房,m表示以下有m行操作,
以下 每行先输入一个数 i ,表示一种操作:
若i为1,表示查询房间,再输入一个数x,表示在1--n 房间中找到长度为x的连续空房,输出连续x个房间
中左端的房间号,尽量让这个房间号最小,若找不到长度为x的连续空房,输出0。若找得到,在这x个空
房间中住上人。
若i为2,表示退房,再输入两个数 x,y 代表 房间号 x---x+y-1 退房,即让房间为空。
输入:
10 6
1 3
1 3
1 3
1 3
2 5 5
1 6
输出:
1
4
7
0
5
首先我们看完题目后肯定会需要维护一个区间最长的连续空间.
而对于维护这一个性质,我们就需要知道一个区间从左端点开始的最长的连续空间以及从右端点开始的最长的连续空间.这样的话在我们进行区间合并的时候才能维护出区间最长的连续空间
那么此时我们的问题就变成了如何找到最早出现的长度为x的连续空区间.我们可以使用线段树的二分性质来做.
int query(int v,int rt) {
if(tree[rt].l==tree[rt].r) return tree[rt].l;
if(tree[rt].lazy!=-1) pushdown(rt);
if(v<=tree[ls].sum) return query(v,ls);
else if(tree[ls].rmax+tree[rs].lmax>=v) return tree[ls].r-tree[ls].rmax+1;
else return query(v,rs);
}
现在仔细的讲一下我们的 q u e r y query query部分,我们先不断的判断左子树的最长连续空间是否比x在,如果比x大的话就意味着我们的要找的区间肯定在左子树上,然后当我们发现此时的左子树不够时,此时意味着什么,因为我们上一次是够的,说明此时的区间要么在右子树上,要么是横跨了左右子树(不完全在左子树上).那么这样的话,我们肯定是需要判断后者情况,因为后者的左端点在前者的前面,符合题意找到最前的一个情况
下面是具体的代码部分:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
struct Segment_tree{
int l,r,sum,lazy,lmax,rmax;
}tree[maxn*4];
int n,m;
void pushup(Segment_tree &u,Segment_tree &l,Segment_tree &r) {
u.sum=max(l.sum,r.sum);
u.sum=max(u.sum,l.rmax+r.lmax);
u.lmax=l.lmax;u.rmax=r.rmax;
if(l.lmax==l.r-l.l+1) u.lmax+=r.lmax;
if(r.rmax==r.r-r.l+1) u.rmax+=l.rmax;
}
void pushup(int rt) {
pushup(tree[rt],tree[ls],tree[rs]);
}
void build(int l,int r,int rt) {
tree[rt].l=l;tree[rt].r=r;tree[rt].lazy=-1;
if(l==r) {
tree[rt].sum=tree[rt].lmax=tree[rt].rmax=1;
return ;
}
int mid=(l+r)>>1;
build(lson);build(rson);
pushup(rt);
}
void change(int rt,int v) {
int len=tree[rt].r-tree[rt].l+1;
tree[rt].sum=tree[rt].lmax=tree[rt].rmax=(v==1?len:0);
tree[rt].lazy=v;
}
void pushdown(int rt) {
change(ls,tree[rt].lazy);change(rs,tree[rt].lazy);
tree[rt].lazy=-1;
}
void update(int l,int r,int rt,int v) {
if(tree[rt].l==l&&tree[rt].r==r) {
change(rt,v);
return ;
}
if(tree[rt].lazy!=-1) pushdown(rt);
int mid=(tree[rt].l+tree[rt].r)>>1;
if(r<=mid) update(l,r,ls,v);
else if(l>mid) update(l,r,rs,v);
else update(l,mid,ls,v),update(mid+1,r,rs,v);
pushup(rt);
}
int query(int v,int rt) {
if(tree[rt].l==tree[rt].r) return tree[rt].l;
if(tree[rt].lazy!=-1) pushdown(rt);
if(v<=tree[ls].sum) return query(v,ls);
else if(tree[ls].rmax+tree[rs].lmax>=v) return tree[ls].r-tree[ls].rmax+1;
else return query(v,rs);
}
int main() {
n=read();m=read();
build(root);
for(int i=1;i<=m;i++) {
int opt=read();
if(opt==1) {
int x=read();
if(tree[1].sum<x) {
puts("0");
continue;
}
int pos=query(x,1);
printf("%d\n",pos);
update(pos,pos+x-1,1,0);
}
else {
int l=read(),len=read();
update(l,l+len-1,1,1);
}
}
return 0;
}