真是個好題,雖然WA了好幾次,但都是自己SB。。。
包含了線段樹所有的操作,看了這篇博文又加深了一次理解:
http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html
掉進的坑:
(1)因爲每reset一次,就重新build一次,TLE,看了discuss纔想起來,同一個case中reset,用update就行了
(2)build寫在每個case的最前面,但忘了清空vector了,WA了好幾次纔想起來
(3)case之間忘了空行,PE了一次。。。
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define MAX 50005
int N, M;
struct Node{
int l, r;
int tlen, llen, rlen;
int mark;
int mid(){ return (l+r)>>1; }
int len(){ return r-l+1; }
} node[MAX << 2];
struct Range{
int l, r;
Range(): l(0), r(0){}
Range(const Range& r): l(r.l), r(r.r){}
bool operator < (int x)const{
return r < x;
}
};
vector<Range> used;
inline void pushDown(int x)
{
if(node[x].mark != -1) node[x<<1].mark = node[x<<1|1].mark = node[x].mark;
}
inline void pushUp(int x)
{
if(node[x<<1].mark == node[x<<1|1].mark) node[x].mark = node[x<<1].mark;
else node[x].mark = -1;
node[x].tlen = max(node[x<<1].rlen+node[x<<1|1].llen,
max(node[x<<1].tlen, node[x<<1|1].tlen)
);
if(node[x<<1].llen == node[x<<1].len())
node[x].llen = node[x<<1].llen + node[x<<1|1].llen;
else
node[x].llen = node[x<<1].llen;
if(node[x<<1|1].rlen == node[x<<1|1].len())
node[x].rlen = node[x<<1|1].rlen + node[x<<1].rlen;
else
node[x].rlen = node[x<<1|1].rlen;
}
void update(int x, int L, int R, int tag)
{
if(node[x].l >= L && node[x].r <= R){
if(tag) node[x].tlen = node[x].llen = node[x].rlen = 0;
else node[x].tlen = node[x].llen = node[x].rlen = node[x].len();
node[x].mark = tag;
}
else{
pushDown(x);
int m = node[x].mid();
if(m >= R) update(x<<1, L, R, tag);
else if(m < L) update(x<<1|1, L, R, tag);
else{
update(x<<1, L, m, tag);
update(x<<1|1, m+1, R, tag);
}
pushUp(x);
}
}
void build(int x, int l, int r)
{
node[x].l = l;
node[x].r = r;
node[x].mark = 0;
node[x].tlen = node[x].llen = node[x].rlen = node[x].len();
if(l == r) return;
int m = node[x].mid();
build(x<<1, l, m);
build(x<<1|1, m+1, r);
}
int alloc(int x, int n)
{
int lc = x<<1, rc = x<<1|1;
//check starting from left end
if(node[x].llen >= n){
return node[x].l;
}
//check left subtree
if(node[lc].tlen >= n){
return alloc(lc, n);
}
//check left + right
if(node[lc].rlen + node[rc].llen >= n){
return node[lc].r-node[lc].rlen+1;
}
//check right subtree
if(node[rc].tlen >= n){
return alloc(rc, n);
}
//should never reach here
return 0;
}
int New(int n)
{
if(n <= 0 || node[1].tlen < n) return 0;
Range block;
block.l = alloc(1, n);
block.r = block.l+n-1;
int i = lower_bound(used.begin(), used.end(), block.l) - used.begin();
used.insert(used.begin() + i, block);
update(1, block.l, block.r, 1);
return block.l;
}
Range Free(int x)
{
if(used.empty()) return Range();
//find block that contains x
int i = lower_bound(used.begin(), used.end(), x) - used.begin();
if(i >= used.size() || used[i].l > x) return Range();
//mark the range unused
Range res = used[i];
update(1, used[i].l, used[i].r, 0);
used.erase(used.begin() + i);
return res;
}
int Get(int n)
{
if(n < 1 || n > used.size()) return 0;
return used[n-1].l;
}
void Reset()
{
for(int i = 0; i < used.size(); ++i){
update(1, used[i].l, used[i].r, 0);
}
used.clear();
}
int main()
{
int s, n;
char cmd[8];
Range block;
while(~scanf("%d%d", &N, &M)){
build(1, 1, N);
while(M--){
scanf("%s", cmd);
if(cmd[0] == 'N'){
scanf("%d", &n);
s = New(n);
if(s) printf("New at %d\n", s);
else puts("Reject New");
}
else if(cmd[0] == 'F'){
scanf("%d", &n);
block = Free(n);
if(block.l) printf("Free from %d to %d\n", block.l, block.r);
else puts("Reject Free");
}
else if(cmd[0] == 'G'){
scanf("%d", &n);
s = Get(n);
if(s) printf("Get at %d\n", s);
else puts("Reject Get");
}
else{
puts("Reset Now");
Reset();
}
}
puts("");
}
return 0;
}