非常细腻的线段树题目啊,后来还是有个细节写错了,查了一个晚上。。就不分析了。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <utility> #include <cstdlib> using namespace std; #define N 80011 struct node { int ls,rs,ms; int pos; int mark; // 0: unsure 1: all-empty 2: all-full }tree[4*N]; int n,m; void build(int l,int r,int rt) { tree[rt].ls = tree[rt].rs = tree[rt].ms = r-l+1; tree[rt].pos = l; if(l == r) { return; } int mid = (l+r)/2; build(l,mid,2*rt); build(mid+1,r,2*rt+1); } int if_all_empty(int l,int r,int rt) { if(tree[rt].ls == r-l+1) return 1; return 0; } void update(int l,int r,int rt) { if(!tree[rt].mark) return; if(tree[rt].mark == 1) //全空,则下传给左右子树 { int len = r-l+1; tree[2*rt].ls = tree[2*rt].rs = tree[2*rt].ms = (len+1)/2; tree[2*rt].pos = l; tree[2*rt+1].ls = tree[2*rt+1].rs = tree[2*rt+1].ms = len/2; tree[2*rt+1].pos = (l+r)/2+1; tree[2*rt].mark = tree[2*rt+1].mark = 1; } else if(tree[rt].mark == 2) //全满,则下传给左右子树 { tree[2*rt].ls = tree[2*rt].rs = tree[2*rt].ms = 0; tree[2*rt].pos = l; tree[2*rt+1].ls = tree[2*rt+1].rs = tree[2*rt+1].ms = 0; tree[2*rt+1].pos = (l+r)/2+1; tree[2*rt].mark = tree[2*rt+1].mark = 2; } tree[rt].mark = 0; // not "== 0" } int query(int l,int r,int dis,int rt) { update(l,r,rt); if(tree[rt].ms<dis) return 0; if(tree[rt].ms == dis) return tree[rt].pos; int mid = (l+r)/2; if(tree[2*rt].ms>=dis) return query(l,mid,dis,2*rt); if(tree[2*rt].rs + tree[2*rt+1].ls>=dis) return mid - tree[2*rt].rs + 1; return query(mid+1,r,dis,2*rt+1); } void in_out(int l,int r,int aa,int bb,int flag,int rt) //flag == 1: insert else quit { if(aa>r||bb<l) return; if(aa<=l&&bb>=r) { if(flag == 1) //如果当前要入住 { tree[rt].ls = tree[rt].rs = tree[rt].ms = 0; tree[rt].pos = l; tree[rt].mark = 2; } else //如果当前要退房 { tree[rt].ls = tree[rt].rs = tree[rt].ms = r-l+1; tree[rt].pos = l; tree[rt].mark = 1; } return; } update(l,r,rt); int mid = (l+r)/2; in_out(l,mid,aa,bb,flag,2*rt); in_out(mid+1,r,aa,bb,flag,2*rt+1); tree[rt].ls = tree[2*rt].ls; if(if_all_empty(l,mid,2*rt)) tree[rt].ls += tree[2*rt+1].ls; tree[rt].rs = tree[2*rt+1].rs; if(if_all_empty(mid+1,r,2*rt+1)) tree[rt].rs += tree[2*rt].rs; tree[rt].ms = max(tree[2*rt].rs+tree[2*rt+1].ls,max(tree[2*rt].ms,tree[2*rt+1].ms)); if(tree[rt].ms == tree[2*rt].ms) //如果当前区间最大空房数等于左子树最大空房数 tree[rt].pos = tree[2*rt].pos; //则起点置为左子树的起点 else if(tree[rt].ms == tree[2*rt].rs + tree[2*rt+1].ls) //同理 tree[rt].pos = mid - tree[2*rt].rs + 1; else tree[rt].pos = tree[2*rt+1].pos; } int main() { scanf("%d%d",&n,&m); memset(tree,0,sizeof(tree)); build(1,n,1); int i,flag; int x,dis; for(i=0;i<m;i++) { scanf("%d",&flag); if(flag == 1) { scanf("%d",&dis); int ans = query(1,n,dis,1); printf("%d\n",ans); if(ans) in_out(1,n,ans,ans+dis-1,1,1); } else if(flag == 2) { scanf("%d%d",&x,&dis); in_out(1,n,x,x+dis-1,2,1); } } return 0; }