题意:每次插入一个线段,或删除一个已存在的线段,每次插入后输出当前插入的线段能完整覆盖存在的几条线段。
思路:一个线段被另一个线段只需要它的两个端点都在另一个线段之间即可。
用两个树状数组分别记录线段左右端点的位置,因为是按线段长度顺序插入的,所以只可能有以下五种情况
所以对于当前查询的区间[l, r]答案就是左端点在l之后的线段减去右端点在r之后的线段之差。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 400010;
//const int INF = 0x3f3f3f3f;
int n, m;
int c[2][MAXN];
int tmp[MAXN];
struct Line {
int l, r;
} line[MAXN];
struct Op {
int t, id;
} op[MAXN];
int lowbit(int x) {
return x & -x;
}
void Update(int x, int d, int id) {
while(x <= m) {
c[id][x] += d;
x += lowbit(x);
}
}
int Sum(int x, int id) {
int ret = 0;
while(x > 0) {
ret += c[id][x];
x -= lowbit(x);
}
return ret;
}
int main() {
//freopen("input.txt", "r", stdin);
int kase = 0;
while(cin >> n) {
memset(c, 0, sizeof(c));
int cnt = 0;
for(int i = 0, t, u; i < n; i++) {
scanf("%d", &t);
op[i].t = t;
if(!t) {
scanf("%d", &u);
line[cnt].l = u;
line[cnt].r = u + cnt + 1;
tmp[cnt<<1] = u;
tmp[(cnt<<1)^1] = u + cnt + 1;
op[i].id = cnt;
cnt++;
}
else {
scanf("%d", &u);
u--;
op[i].id = u;
}
}
sort(tmp, tmp+cnt*2);
m = unique(tmp, tmp+cnt*2) - tmp;
for(int i = 0; i < cnt; i++) {
line[i].l = lower_bound(tmp, tmp+m, line[i].l) - tmp + 1;
line[i].r = lower_bound(tmp, tmp+m, line[i].r) - tmp + 1;
}
printf("Case #%d:\n", ++kase);
cnt = 0;
for(int i = 0, ans; i < n; i++) {
if(!op[i].t) {
ans = Sum(m, 0)-Sum(line[cnt].l-1, 0) - (Sum(m, 1)-Sum(line[cnt].r, 1));
printf("%d\n", ans);
Update(line[cnt].l, 1, 0);
Update(line[cnt].r, 1, 1);
cnt++;
}
else {
Update(line[op[i].id].l, -1, 0);
Update(line[op[i].id].r, -1, 1);
}
}
}
return 0;
}