题目地址:
https://www.luogu.com.cn/problem/P2184
题目背景:
面对蚂蚁们的疯狂进攻,小FF的Tower defence宣告失败……人类被蚂蚁们逼到了Greed Island上的一个海湾。现在,小FF的后方是一望无际的大海,前方是变异了的超级蚂蚁。小FF还有大好前程,他可不想命丧于此, 于是他派遣手下最后一批改造SCV布置地雷以阻挡蚂蚁们的进攻。
题目描述:
小FF最后一道防线是一条长度为
n
n
n的战壕,小FF拥有无数多种地雷,而SCV每次可以在
[
L
,
R
]
[L, R]
[L,R]区间埋放同一种不同于之前已经埋放的地雷。由于情况已经十万火急,小FF在某些时候可能会询问你在
[
L
′
,
R
′
]
[L',R']
[L′,R′]区间内有多少种不同的地雷,他希望你能尽快的给予答复。
输入格式:
第一行为两个整数
n
n
n和
m
m
m,
n
n
n表示防线长度,
m
m
m表示SCV布雷次数及小FF询问的次数总和。
接下来有
m
m
m行,每行三个整数
q
,
l
,
r
q,l,r
q,l,r:
若
q
=
1
q=1
q=1,则表示SCV在
[
l
,
r
]
[l, r]
[l,r]这段区间布上一种地雷;
若
q
=
2
q=2
q=2,则表示小FF询问当前
[
l
,
r
]
[l, r]
[l,r]区间总共有多少种地雷。
输出格式:
对于小FF的每次询问,输出一个答案(单独一行),表示当前区间地雷总数。
数据范围:
对于
30
%
30\%
30%的数据,
0
≤
n
0 \le n
0≤n,
m
≤
1000
m \le 1000
m≤1000。
对于
100
%
100\%
100%的数据,
0
≤
n
0 \le n
0≤n,
m
≤
1
0
5
m \le 10^5
m≤105。
询问的时候,其实就是问,所有的区间有多少个起点在 [ 1 , r ] [1, r] [1,r],有多少个终点在 [ 1 , l − 1 ] [1,l-1] [1,l−1],两个相减即为 [ l , r ] [l,r] [l,r]这个区间有多少种不同的地雷。对于起点,其实就是要做单点修改和求前缀和,从而可以用树状数组做。对起点和终点各自开一个树状数组即可。代码如下:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int tr[2][N];
#define lowbit(x) (x & -x)
void add(int i, int k, int x) {
for (; k <= n; k += lowbit(k)) tr[i][k] += x;
}
int sum(int i, int k) {
int res = 0;
for (; k; k -= lowbit(k)) res += tr[i][k];
return res;
}
int main() {
scanf("%d%d", &n, &m);
while (m--) {
int q, l, r;
scanf("%d%d%d", &q, &l, &r);
if (q == 1) add(0, l, 1), add(1, r, 1);
else printf("%d\n", sum(0, r) - sum(1, l - 1));
}
}
每次操作时间复杂度 O ( log n ) O(\log n) O(logn),空间 O ( n ) O(n) O(n)。