题意:停车场有n(1<=n<=2*10^5)个停车位,从左到右依次编号为1到n。有两种共m(1<=m<=2*10^5)次操作:“1 id”表示编号为id的车驶入停车场并停车;“2 id”表示编号为id的车驶出停车场。停车时有一个要求,就是将车停在离其它车尽量远的位置,如果有多个位置可选,选择最左边的那个。
分析:根据题目要求及数据范围,很快就能确定要用线段树来解决。本题细节比较多,WA了很多次。
首先,我开始时想当然的认为每次停车时,找到[1, n]区间内最长且最左边的连续的空闲区间(设起始位置为start,结束位置为end),那么停车的位置就是(start - end + 2) / 2(start为1或end为n时要特殊处理),但这样却过不了样例。于是,我模拟了一下样例的停车过程,发现了问题:
设n为7,那么当停车情况为“0 1 0 1 0 0 1”时(0表示没车,1表示有车),下一辆车应该停在第1个车位,而我得到的结果是将车停在第5个车位。
所以,只维护区间内最长的连续空闲区间是不够的,因为车不一定停在最长的那个连续空闲区间内。好了,就说这么多,附上代码:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int maxn = 200010; int n, m; /* llen: 区间左端点开始连续的空位的长度 rlen: 区间右端点开始连续的空位的长度 mlen: 整个区间最长的连续的空位的长度 */ int llen[maxn<<2], mlen[maxn<<2], rlen[maxn<<2]; /* start: 如果将车停在该区间,停车的位置所在的连续空位的起始位置 end: 如果将车停在该区间,停车的位置所在的连续空位的结束位置 ms: 该区间最长的连续的空位的起始位置 */ int start[maxn<<2], end[maxn<<2], ms[maxn<<2]; int pos[maxn*5]; void pushUp(int l, int r, int rt) { int m = (l + r) >> 1; llen[rt] = llen[rt<<1]; rlen[rt] = rlen[rt<<1|1]; if (llen[rt] == m - l + 1) { llen[rt] += llen[rt<<1|1]; } if (rlen[rt] == r - m) { rlen[rt] += rlen[rt<<1]; } /*求区间最长的连续空位的长度及起始位置*/ if (mlen[rt<<1] >= (rlen[rt<<1] + llen[rt<<1|1]) && mlen[rt<<1] >= mlen[rt<<1|1]) { mlen[rt] = mlen[rt<<1]; ms[rt] = ms[rt<<1]; } else if (rlen[rt<<1] + llen[rt<<1|1] >= mlen[rt<<1|1]) { mlen[rt] = rlen[rt<<1] + llen[rt<<1|1]; ms[rt] = m - rlen[rt<<1] + 1; } else { mlen[rt] = mlen[rt<<1|1]; ms[rt] = ms[rt<<1|1]; } /*求如果将车停在该区间,停车的位置所在的连续空位的起始及结束的位置*/ int dis, dis1, dis2; dis1 = (mlen[rt<<1] + 1) / 2; dis2 = (mlen[rt<<1|1] + 1) / 2; dis = (rlen[rt<<1] + llen[rt<<1|1] + 1) / 2; if (dis1 >= dis && dis1 >= dis2) { start[rt] = start[rt<<1]; end[rt] = end[rt<<1]; } else if (dis >= dis2) { start[rt] = m - rlen[rt<<1] + 1; end[rt] = m + llen[rt<<1|1]; } else { start[rt] = start[rt<<1|1]; end[rt] = end[rt<<1|1]; } return ; } void build(int l, int r, int rt) { if (l == r) { llen[rt] = mlen[rt] = rlen[rt] = 1; ms[rt] = start[rt] = end[rt] = l; return ; } int m = (l + r) >> 1; build(l, m, rt << 1); build(m + 1, r, rt << 1 | 1); pushUp(l, r, rt); } void update(int l, int r, int rt, int p, int c) { if (l == r) { llen[rt] = mlen[rt] = rlen[rt] = c; ms[rt] = start[rt] = end[rt] = l; return ; } int m = (l + r) >> 1; if (p <= m) { update(l, m, rt << 1, p, c); } else { update(m + 1, r, rt << 1 | 1, p, c); } pushUp(l, r, rt); } int main() { //freopen("parking.in", "r", stdin); //freopen("parking.out", "w", stdout); scanf("%d%d", &n, &m); build(1, n, 1); int t, id; int from, to, len; for (int i = 0; i < m; ++i) { scanf("%d%d", &t, &id); if (t == 1) { from = start[1]; to = end[1]; len = to - from + 1; // 这里一开始只写了llen[1] >= (len + 1) / 2,WA一次 if (llen[1] >= (len + 1) / 2 && llen[1] >= rlen[1]) { update(1, n, 1, 1, 0); pos[id] = 1; } else if (rlen[1] > (len + 1) / 2) { update(1, n, 1, n, 0); pos[id] = n; } else { update(1, n, 1, (from + to) / 2, 0); pos[id] = (from + to) / 2; } printf("%d\n", pos[id]); } else { update(1, n, 1, pos[id], 1); } } return 0; }