【题解】
把车开走操作的x指的是n个操作里面的第x个操作对应的车。
这题好坑啊,也怪自己没看清题目。它说的是长度为L。。
0..L说的是点。然后相邻两个点之间的距离为1,这样就组成长度为L的一段路了-_-.
我们不要管他。就变成0..L-1
这样每个点就代表一个距离了。而不是真的是一个点。。
然后我们在这条路的前边扩充b,在后边扩充f
整个区间就变成[-b..L-1+f]了(线段树不管你区间是不是负都可以的^_^)
输入的车的长度是x
那么问题就转换成在这个区间内找一段x+b+f的连续空位置。
假设找到的最左端的位置是pos;
那么pos+b就是要输出的答案了。
然后占据的时候不是占据pos..pos+b+f+x
而应该占据pos+b..pos+x-1
但我觉得这个问题还是有点BUG的。
就是后面进来的车停在了前面进来的车的前面b单位长度处。那么如果f>b,前面那辆车不就不满足要求了吗。。。(路人:出题人就是爷,你管他呢)
找连续空位置的话。
记录llx[rt],rlx[rt],lx[rt]分别表示这个节点从最左开始连续的空位置数目,这个节点从最右开始连续的空位置数目,整个区间不管哪里,连续的空位置数目。
然后所求的连续空位置有3种可能。
1.全部在左区间
2.全部在右区间。
3.横跨两个区间。
所以得到lx[rt] = max(lx[rt<<1],lx[rt<<1|1],rlx[rt<<1]+llx[rt<<1|1]);
因为连续区间块的时候要尽量往左。
所以先递归左儿子。然后是横跨中间的情况(如果是这种情况就可以直接输出起始位置了);最后是右儿子;
【代码】
#include <cstdio> #include <algorithm> #define lson begin,m,rt<<1 #define rson m+1,end,rt<<1|1 using namespace std; const int MAXL = 101000; struct data2 { int l,r; }; data2 qujian[101]; int l, b, f, n; int cover[MAXL * 4],llx[MAXL*4],rlx[MAXL*4],lx[MAXL*4]; void push_up(int rt,int len) { lx[rt] = max(lx[rt << 1], lx[rt << 1 | 1]); lx[rt] = max(lx[rt], rlx[rt << 1] + llx[rt << 1 | 1]); llx[rt] = llx[rt << 1]; if (llx[rt] == (len - (len >> 1))) //如果左区间全是连续的空位置。 llx[rt] += llx[rt << 1 | 1];//则加上右区间从最左开始的连续空位置数目。 rlx[rt] = rlx[rt << 1 | 1]; if (rlx[rt] == (len >> 1)) rlx[rt] += rlx[rt << 1]; } void build(int begin, int end, int rt) { cover[rt] = 0; if (begin == end) { llx[rt] = rlx[rt] = lx[rt] = 1; return; } int m = (begin + end) >> 1; build(lson); build(rson); push_up(rt,end-begin+1); } void input_data() { scanf("%d%d%d", &l, &b, &f); build(-b, l + f -1, 1); } void push_down(int rt,int len) { if (cover[rt] != -1) { cover[rt << 1] = cover[rt << 1 | 1] = cover[rt]; if (cover[rt] == 1) { llx[rt << 1] = rlx[rt << 1] = lx[rt << 1] = 0; llx[rt << 1| 1] = rlx[rt << 1 | 1] = lx[rt << 1 | 1] = 0; } else { llx[rt << 1] = rlx[rt << 1] = lx[rt << 1] = len - (len >> 1); llx[rt << 1 | 1] = rlx[rt << 1 | 1] = lx[rt << 1 | 1] = len >> 1; } cover[rt] = -1; } } int query(int len, int begin, int end, int rt) { if (begin == end) return begin; push_down(rt,end - begin+1); int m = (begin + end) >> 1; if (lx[rt << 1] >= len) return query(len, lson); else if (rlx[rt << 1] + llx[rt << 1 | 1] >= len) return m - rlx[rt << 1] + 1; //返回的这个坐标可以手算模拟下。 else return query(len, rson); } void up_data(int l, int r, int num, int begin, int end, int rt) //用于更新节点。 { if (l <= begin && end <= r) { cover[rt] = num; if (num == 1) { llx[rt] = rlx[rt] = lx[rt] = 0; return; } else { llx[rt] = rlx[rt] = lx[rt] = end - begin + 1; } return; } push_down(rt,end - begin+1); int m = (begin + end) >> 1; if (l <= m) up_data(l, r, num, lson); if (m < r) up_data(l, r, num, rson); push_up(rt, end - begin + 1); } void output_ans() { scanf("%d", &n); for (int i = 1; i <= n; i++) { int op, x; scanf("%d%d", &op, &x); if (op == 1) { int len = x + b + f; if (len > lx[1]) printf("-1 "); else { int qidian = query(len, -b, l + f - 1, 1); int cl, cr; cl = qidian + b; //[cl,cr]是要修改的区间。 cr = cl + x - 1; qujian[i].l = cl; qujian[i].r = cr; up_data(cl, cr, 1, -b, l + f - 1, 1); printf("%d ", qidian+b); } } else { int zuo, you; zuo = qujian[x].l; you = qujian[x].r; up_data(zuo, you, 0, -b, l + f - 1, 1); } } } int main() { //freopen("F:\rush.txt", "r", stdin); //freopen("F:\rush_out.txt", "w", stdout); input_data(); output_ans(); return 0; }