题意:
N间空房子,M次操作,接下来M行,每行先输入一个整数a,a=1时再输入一个数b,查询N间房子里面是否有b间连续的空房子,如果有返回最左边的空房间编号,如果a=2,接着输入两个数b,c,表示将[b,c]区间所有房间清空。
直接上代码吧,没什么好说的,合并操作在上一篇已经讲过了,上题是这题的加强版
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 50005; /* *线段树操作:update:区间替换 query:询问满足条件的最左端点 */ struct Node { int l,r; int lsum,rsum,msum; int ck; int mid(){return (l+r)>>1;} }tree[N<<2]; void PushDown(int rt) { if(tree[rt].ck != -1) { int ll = tree[rt<<1].r - tree[rt<<1].l + 1; int rr = tree[rt<<1|1].r - tree[rt<<1|1].l + 1; tree[rt<<1].ck = tree[rt<<1|1].ck = tree[rt].ck; tree[rt].ck = -1; tree[rt<<1].rsum = tree[rt<<1].lsum = tree[rt<<1].msum = tree[rt<<1].ck ?0:ll; tree[rt<<1|1].rsum = tree[rt<<1|1].lsum = tree[rt<<1|1].msum = tree[rt<<1|1].ck ?0:rr; } } void PushUp(int rt) { int ll = tree[rt<<1].r - tree[rt<<1].l + 1; int rr = tree[rt<<1|1].r - tree[rt<<1|1].l + 1; tree[rt].lsum = tree[rt<<1].lsum; if(tree[rt<<1].lsum == ll) tree[rt].lsum += tree[rt<<1|1].lsum; tree[rt].rsum = tree[rt<<1|1].rsum; if(tree[rt].rsum == rr) tree[rt].rsum += tree[rt<<1].rsum; tree[rt].msum = max(max(tree[rt<<1].msum,tree[rt<<1|1].msum),tree[rt<<1].rsum+tree[rt<<1|1].lsum); } void build(int l,int r,int rt) { tree[rt].l = l,tree[rt].r = r,tree[rt].ck = -1; tree[rt].lsum = tree[rt].rsum = tree[rt].msum = r-l+1; if(l == r) 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 rt) { if(tree[rt].l == l && tree[rt].r == r) { tree[rt].msum = tree[rt].lsum = tree[rt].rsum = c?0:(r-l+1); tree[rt].ck = c; return; } PushDown(rt); int m = tree[rt].mid(); if(r<=m) update(l,r,c,rt<<1); else if(l>m) update(l,r,c,rt<<1|1); else { update(l,m,c,rt<<1); update(m+1,r,c,rt<<1|1); } PushUp(rt); } int query(int w,int rt) { if (tree[rt].l == tree[rt].r) return tree[rt].l; PushDown(rt); int m = tree[rt].mid(); if (tree[rt<<1].msum >= w)//如果左子树的最大连续空>=需求量,那么直接进入左子树,=也去左子树的原因是题目要求的最左 return query(w , rt<<1); //中间的 else if (tree[rt<<1].rsum + tree[rt<<1|1].lsum >= w)//左子树的连续右+右子树的连续左>=w,说明找到了可以直接求出 return m - tree[rt<<1].rsum + 1; return query(w , rt<<1|1); } int main() { int n,m; while(~scanf("%d %d",&n,&m)) { build(1,n,1); while(m--) { int op,a,b; scanf("%d",&op); if(op == 1) { scanf("%d",&a); if(tree[1].msum < a) puts("0");//根节点的最大连续空间不够 else { int p = query(a,1); printf("%d\n",p); update(p,p+a-1,1,1);//把这段更新为被覆盖 } } else { scanf("%d %d",&a,&b); update(a,a+b-1,0,1);//把这段更新为未被覆盖 } } } return 0; }