POJ-2892: Tunnel Warfare 树状数组+二分
主要参考了这篇博客 http://blog.jobbole.com/96430/ 比较详细地介绍了树状数组的各方面应用。
感觉比较难写的是二分,最好多加几个 Query 测试二分写对没有。
// Tunnel Warfare
// http://poj.org/problem?id=2892
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cassert>
#include <stack>
using namespace std;
typedef long long LL;
const int maxn = 50000 + 10;
int n, m;
bool good[maxn];
int pres[maxn];
stack<int> des;
inline int lowbit(int x) {
return x & -x;
}
void add(int *arr, int x, int v) {
for (int i = x; i < maxn; i += lowbit(i)) {
arr[i] += v;
}
}
LL sum(int *arr, int x) {
LL s = 0;
for (int i = x; i ; i -= lowbit(i)) {
s += arr[i];
}
return s;
}
int main() {
scanf("%d%d\n", &n, &m);
for (int i = 1; i <= n; i++) {
good[i] = true;
add(pres, i, 1);
}
good[0] = good[n+1] = false;
pres[0] = pres[n+1] = 0;
int lastDes = -1;
for (int i = 1; i <= m; i++) {
char cmd;
int opn;
scanf("%c", &cmd);
switch (cmd) {
case 'D':
scanf("%d\n", &opn);
if (good[opn]) {
good[opn] = false;
des.push(opn);
add(pres, opn, -1);
}
break;
case 'R':
scanf("\n");
opn = des.top();
des.pop();
if (!good[opn]) {
good[opn] = true;
add(pres, opn, 1);
}
break;
case 'Q':
scanf("%d\n", &opn);
if (!good[opn]) {
printf("0\n");
} else {
// find closest x in left
int l = 0, r = opn, m;
int lx, rx;
while (l + 1 < r) {
m = (l + r) >> 1;
if (sum(pres, r) - sum(pres, m - 1) == r - m + 1) {
r = m;
} else {
l = m;
}
}
lx = l;
assert(good[l] == false);
// find closest x in right
l = opn, r = n + 1;
while (l + 1 < r) {
m = (l + r) >> 1;
if ( sum(pres, m) - sum(pres, l) == m - l) {
l = m;
} else {
r = m;
}
}
rx = r;
// printf("%d - %d :", lx, rx);
printf("%d\n", rx - lx - 1);
}
break;
default:
break;
}
}
return 0;
}