之前在poj做过hotel题,看到这题时就想到是线段树了。但是这题比hotel多一些操作,这就让我捉急了。这里NEW操作相当于hotel中的入住,Free操作相当于退房,但是又有一点不同,每次给你一个地址,要求知道这个地址是否在使用,在使用的话是被哪个区间使用,在这个操作中借用的别人的想法,利用vector二分查找位置,GET操作由于引用的vector所以操作很简单,在Reset操作时不能重新建树,否则会超时, 要用update进行更新。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 50000+10;
struct ST {
int l, r, lsum, rsum, sum, d;
}v[maxn<<2];
int n, m, data;
char s[11];
struct node {
int s, e;
node(int s, int e):s(s), e(e){}
};
bool cmp(const node &a, const node &b) {
return a.s<b.s;//按开始的位置排序
}
vector<node> vc;
vector<node>::iterator it;
void build(int l, int r, int n) {
v[n].l = l, v[n].r = r;
v[n].lsum = v[n].rsum = v[n].sum = r-l+1;
v[n].d = -1;
if (l==r)
return ;
int mid = (v[n].l + v[n].r) >> 1;
build (l, mid, n<<1);
build(mid+1, r, n<<1|1);
}
inline void pushdown(int n) {
if (v[n].d!=-1) {
v[n<<1].d = v[n<<1|1].d = v[n].d;
int len = (v[n].r-v[n].l+1);
v[n<<1].lsum = v[n<<1].rsum = v[n<<1].sum = v[n].d==1?0:(len-(len>>1));
v[n<<1|1].lsum = v[n<<1|1].rsum = v[n<<1|1].sum = v[n].d==1?0:(len>>1);
v[n].d = -1;
}
}
int query(int size, int n) {
if (v[n].l==v[n].r)
return v[n].l;
int mid = (v[n].l + v[n].r) >> 1;
pushdown(n);
if (v[n<<1].sum>=size) {
return query(size, n<<1);
} else if (v[n<<1].rsum+v[n<<1|1].lsum>=size) {
return mid-v[n<<1].rsum+1;
} else {
return query(size, n<<1|1);
}
}
inline int Max(int x, int y) {
return x>y?x:y;
}
inline void pushup(int n) {
v[n].lsum = v[n<<1].lsum;
v[n].rsum = v[n<<1|1].rsum;
int len = (v[n].r-v[n].l+1);
if (v[n].lsum==(len-(len>>1)))
v[n].lsum += v[n<<1|1].lsum;
if (v[n].rsum==(len>>1))
v[n].rsum += v[n<<1].rsum;
v[n].sum = Max(v[n<<1].rsum+v[n<<1|1].lsum, Max(v[n<<1].sum, v[n<<1|1].sum));
}
void update(int l, int r, int d, int n) {
if (l<=v[n].l && v[n].r<=r) {
v[n].d = d;
v[n].lsum = v[n].rsum = v[n].sum = d==1?0:(r-l+1);
return ;
}
pushdown(n);
int mid = (v[n].l + v[n].r) >> 1;
if (r<=mid) {
update(l, r, d, n<<1);
} else if (l>mid) {
update(l, r, d, n<<1|1);
} else {
update(l, mid, d, n<<1);
update(mid+1, r, d, n<<1|1);
}
pushup(n);
}
int main()
{
while (~scanf("%d%d", &n, &m)) {
build(1, n, 1);
vc.clear();
while (m--) {
scanf("%s", s);
if (s[0]=='N') {
scanf("%d", &data);
if (v[1].sum<data || data<=0) {
printf("Reject New\n");
} else {
int idx = query(data, 1);
update(idx, idx+data-1, 1, 1);
printf("New at %d\n", idx);
node p(idx, idx+data-1);
it = upper_bound(vc.begin(), vc.end(), p, cmp);
vc.insert(it, p);//二分找到比p大的位置,在it之前插入p
}
} else if (s[0]=='F') {
scanf("%d", &data);
node p(data, data);
it = upper_bound(vc.begin(), vc.end(), p, cmp);
//二分p比大的位置,如果p在该位置的前一个位置为合法
int tmp = it-vc.begin()-1;
if (tmp==-1 || data<vc[tmp].s || data>vc[tmp].e) {
printf("Reject Free\n");
} else {
update(vc[tmp].s, vc[tmp].e, 0, 1);
printf("Free from %d to %d\n", vc[tmp].s, vc[tmp].e);
vc.erase(tmp+vc.begin());
}
} else if (s[0]=='G') {
scanf("%d", &data);
int tmp = vc.end()-vc.begin();
if (data>tmp || data<=0) {
printf("Reject Get\n");
} else {
printf("Get at %d\n", vc[data-1].s);
}
} else if (s[0]=='R') {
update(1, n, 0, 1);
printf("Reset Now\n");
vc.clear();
}
}printf("\n");
}
return 0;
}