知识点:线段树
只会线段树,就只能用线段树来做,发现区间端点的范围不大,可以直接来维护,然后发现最重要的一个结论,那么就是我们对区间端点做统计的话,那么一定是成对出现的,因为题目的要求就是删掉和要加入线段有交集的线段,然后再加入线段,所以就是这些端点就是,第一个线段的左端点,第一个的右端点,第二个的左端点,第二个的右端点,以此类推,这样这个题就转化成了两个操作,一个区间修改为0,一个是单点增加,不是单点修改为1,因为我们要加入的区间可能左右端点是相同,然后我们分类讨论就行了,为的是寻找区间修改的左右端点位置,举例,如果要加入区间的两边的端点数区间和都是偶数,那么显然置零区间就是我们要加入的线段,如果两边都是奇数,怎么样,左边奇数右边偶数,左边偶数右边奇数,这样分类讨论一下这个题就行了,里面还用到线段树上二分,寻找第几个1在哪个位置,就算这个序列可能有值为2的点,那么也是可以这样子用的,看别人用的STL代码短时间快,以我的能力就只能先这样了
然后思考一下为什么这个题可以用树状数组做,单点增加不必说,求区间和也是,关键就是那个区间置零操作,很显然这个题我们输入的点的个数最多也就是n,那么删除的点最多也就这么多,如果删除的时候我们能够具体知道要删除的是拿个,单点操作一个一个删除显然是可以的,就是不知道如果把那些需要删除的点一个一个找出来,索性用线段树的区间修改一下推平,
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
struct segt {
int l, r, sum, tag;
} t[N * 4];
int m;
void pushdown(int p) {
if (t[p].tag == -1) return;
int p1 = p * 2, p2 = p * 2 + 1;
t[p1].sum = t[p2].sum = t[p1].tag = t[p2].tag = 0;
t[p].tag = -1;
}
void build(int p, int l, int r) {
t[p].l = l; t[p].r = r; t[p].tag = -1;
if (l == r) return;
int mid = (l + r) / 2;
build(p * 2, l, mid);
build(p * 2 + 1, mid + 1, r);
}
void change(int p, int l, int r, int v) {
if (l <= t[p].l && t[p].r <= r) {
if (!v) t[p].sum = t[p].tag = 0;
else t[p].sum++;
return;
}
pushdown(p);
int mid = (t[p].l + t[p].r) / 2;
if (l <= mid) change(p * 2, l, r, v);
if (r > mid) change(p * 2 + 1, l, r, v);
t[p].sum = t[p * 2].sum + t[p * 2 + 1].sum;
}
inline int ask(int p, int l, int r) {
if (l <= t[p].l && t[p].r <= r) return t[p].sum;
pushdown(p);
int sum = 0, mid = (t[p].l + t[p].r) / 2;
if (l <= mid) sum += ask(p * 2, l, r);
if (r > mid) sum += ask(p * 2 + 1, l, r);
return sum;
}
inline int query(int p, int res) {
if (t[p].l == t[p].r) return t[p].l;
int p1 = p * 2;
pushdown(p);
if (res <= t[p1].sum) return query(p * 2, res);
else return query(p * 2 + 1, res - t[p1].sum);
}
int main() {
build(1, 0, 1e5 + 1);
scanf("%d", &m);
while (m--) {
char op;
int l, r;
scanf("\n%c", &op);
if (op == 'A') {
scanf("%d%d", &l, &r);
int tot = ask(1, 1, 1e5);
int cnt = ask(1, l, r);
int left = ask(1, 1, l - 1);
int right = tot - cnt - left;
int L, R;
if (left % 2 == 0 && right % 2 == 0) {
printf("%d\n", (tot - left - right) / 2);
L = l; R = r;
} else if (left % 2 && right % 2) {
printf("%d\n", tot / 2 - left / 2 - right / 2);
L = query(1, left);
R = query(1, tot - right + 1);
} else if (left % 2 == 0 && right % 2) {
printf("%d\n", (cnt + 1) / 2);
L = l;
R = query(1, left + cnt + 1);
} else {
printf("%d\n", (cnt + 1) / 2);
R = r;
L = query(1, left);
}
change(1, L, R, 0);
change(1, l, l, 1);
change(1, r, r, 1);
} else {
printf("%d\n", ask(1, 1, 1e5) / 2);
}
}
return 0;
}