题目:http://poj.org/problem?id=3667
大意:有N个房间,给出M条语句,“1 a”表示要求查询是否存在连续的a个空的房间,有的话输出最左边的一个,没有的话输出0。“2 a b"表示把从a开始的b个房间清空。
Sample Input
10 6 1 3 1 3 1 3 1 3 2 5 5 1 6
Sample Output
1 4 7 0 5区间更新,区间查找。应用线段树:
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 50005; //query:询问满足条件的最左端点 struct Node { int l,r; int lsum,rsum,msum; //三个值,帮助确定左边,中间,右边 int tag; //tag --> 标记,1是占用的,0是未占用,-1初始化 int mid(){ return (l+r)/2; } }tree[N<<2]; void pushdown(int root)//更新子树tag,lsum,rsum,msum的信息 { if(tree[root].tag != -1) { int l_num = tree[root*2].r - tree[root*2].l + 1; //左子树的长度 int r_num = tree[root*2+1].r - tree[root*2+1].l + 1; //右子树的长度 tree[root*2].tag = tree[root*2+1].tag = tree[root].tag; //要处理 tree[root].tag = -1; //处理过了的 tree[root*2].rsum = tree[root*2].lsum = tree[root*2].msum = tree[root*2].tag ?0:l_num; tree[root*2+1].rsum = tree[root*2+1].lsum = tree[root*2+1].msum = tree[root*2+1].tag ?0:r_num; } } void pushup(int root)//更新父节点lsum,rsum,msum的信息,msum是最大的sum { int l_num = tree[root*2].r - tree[root*2].l + 1; int r_num = tree[root*2+1].r - tree[root*2+1].l + 1; tree[root].lsum = tree[root*2].lsum; if(tree[root*2].lsum == l_num) tree[root].lsum += tree[root*2+1].lsum; //可向右拓展,越过中间 tree[root].rsum = tree[root*2+1].rsum; if(tree[root].rsum == r_num) tree[root].rsum += tree[root*2].rsum; //可向左拓展,越过中间 tree[root].msum = max(max(tree[root*2].msum,tree[root*2+1].msum),tree[root*2].rsum+tree[root*2+1].lsum); } void build(int l,int r,int root) { tree[root].l = l,tree[root].r = r,tree[root].tag = -1; tree[root].lsum = tree[root].rsum = tree[root].msum = r-l+1; if(l == r) return; int m = (l+r)>>1; build(l,m,root*2); build(m+1,r,root*2+1); pushup(root); } void update(int l,int r,int tg,int root) { if(tree[root].l == l && tree[root].r == r) { tree[root].msum = tree[root].lsum = tree[root].rsum = tg?0:(r-l+1); tree[root].tag = tg; return; } pushdown(root); //更新子树信息 int m = tree[root].mid(); if(r<=m) update(l,r,tg,root*2); else if(l>m) update(l,r,tg,root*2+1); else { update(l,m,tg,root*2); update(m+1,r,tg,root*2+1); } pushup(root); //回溯信息。 } int query(int w,int root) { if (tree[root].l == tree[root].r) return tree[root].l; pushdown(root); //依据tag更新信息再统计 int m = tree[root].mid(); if (tree[root*2].msum >= w) return query(w,root*2); //这段代码很重要 else if (tree[root*2].rsum + tree[root*2+1].lsum >= w)//中间的情况 return m - tree[root*2].rsum + 1; //主要依靠中间区域和叶子节点返回信息 return query(w,root*2+1); //右边 } int main() { //freopen("cin.txt","r",stdin); int n,m; while(cin>>n>>m) { build(1,n,1); while(m--) { int p; scanf("%d",&p); if(p == 1) { int a; scanf("%d",&a); if(tree[1].msum < a) puts("0"); else { int ans = query(a,1); printf("%d\n",ans); update(ans,ans+a-1,1,1); } } else { int a,b; scanf("%d %d",&a,&b); update(a,a+b-1,0,1); } } } return 0; }