题目描述
Bobo 精通数据结构!他想维护一个线段的集合 S。初始时,S 为空。他会依次进行 q 次操作,操作有 2 种。
- 类型 1:给出 l, r,向集合 S 中插入线段 [l, r].
- 类型 2:给出 l, r,询问满足
[
x
,
y
]
∈
S
[x, y] \in S
[x,y]∈S且
x
≤
l
≤
r
≤
y
x \leq l \leq r \leq y
x≤l≤r≤y 的线段 [x, y] 数量。
帮 Bobo 求出每次询问的答案。
求区间
[
l
,
r
]
[l,r]
[l,r]满足条件的线段
问题转化为求
1.区间
[
l
+
1
,
n
]
[l+1,n]
[l+1,n]中存在多少条线段的左端点(这个区间的有线段的左端点出现说明者条线段不完全覆盖)
2.区间
[
1
,
r
−
1
]
[1,r-1]
[1,r−1]中存在多少条线段的右端点(同理上)
答案等于当前线段的条数减去上面不满足要求的条数(容斥原理)
用简单的权值线段树维护上述值
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
auto tmp = { (cout << args << ' ', 0)... };
cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 1e5+5;
const ll INF = 0x7fffffff;
const long double MOD = 1e9 + 7;
struct tr{
struct nodel {
int l, r;
int cnt;
}tree[N << 2];
void push_up(int root) {
tree[root].cnt = tree[root << 1].cnt + tree[root << 1 | 1].cnt;
}
void build(int root, int l, int r) {
if (l == r) tree[root] = { l,r,0 };
else {
tree[root] = { l,r };
int mid = l + r >> 1;
build(root << 1, l, mid);
build(root << 1 | 1, mid + 1, r);
push_up(root);
}
}
void modify(int root, int pos) {
if (tree[root].l == tree[root].r && tree[root].l == pos) {
tree[root].cnt++;
return;
}
int mid = tree[root].l + tree[root].r >> 1;
if (pos <= mid)modify(root << 1, pos);
if (pos > mid)modify(root << 1 | 1, pos);
push_up(root);
}
ll query(int root, int l, int r) {
if (l <= tree[root].l && tree[root].r <= r)return tree[root].cnt;
int mid = tree[root].l + tree[root].r >> 1;
if (r <= mid)return query(root << 1, l, r);
else if (l > mid)return query(root << 1 | 1, l, r);
else {
ll left = query(root << 1, l, r);
ll right = query(root << 1 | 1, l, r);
ll ans;
ans = left + right;
return ans;
}
}
}treel,treer;
int main() {
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, q;
while (cin >> n >> q) {
n += 2;//扩大下区间
treel.build(1, 1, n);
treer.build(1, 1, n);
int cnt = 0;
for (int i = 0; i < q; i++) {
int t, l, r;
cin >> t >> l >> r;
l++;//从2开始
r++;
if (t == 1) {
treel.modify(1, l);
treer.modify(1, r);
cnt++;
}
else {
cout << cnt - treel.query(1, min(l + 1, n), n) - treer.query(1, 1, max(r - 1, 1)) << "\n";
}
}
}
return 0;
}