题面
解题思路
使用莫队+树状数组的做法是显然的,但是复杂度是
O
(
n
n
l
o
g
n
)
O(n \sqrt{nlogn})
O(nnlogn)。
介绍一种基于二次离线的做法,复杂度
O
(
n
n
)
O(n\sqrt n)
O(nn)。
在莫队区间移动时,例如从
[
l
,
r
]
[l,r]
[l,r]变成
[
l
,
r
+
1
]
[l,r+1]
[l,r+1]时,我们需要求得
[
l
,
r
]
[l,r]
[l,r]中有对少个数和r+1有关。这可以拆分成对于
[
1
,
l
−
1
]
[1,l-1]
[1,l−1]和
[
1
,
r
]
[1,r]
[1,r]的两个前缀的询问。由于前缀只有
n
n
n个,我们采用
O
(
n
)
O(\sqrt n)
O(n)修改,
O
(
1
)
O(1)
O(1)查询的数据结构,分块即可。
因此我们可以将莫队区间每次移动的复杂度优化到了
O
(
1
)
O(1)
O(1),整体
O
(
n
n
)
O(n\sqrt n)
O(nn)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e4 + 100;
const int SZ = 223;
int aa[N], bb[N];
void add(int id, int x) {
while (id % SZ != 0) aa[id++] += x;
while (id < N) bb[id / SZ] += x, id += SZ;
}
int query(int id) {
return aa[id] + bb[id / SZ];
}
struct node{
int l, r, id;
}qu[N];
bool operator < (node a, node b) {
if (a.l / SZ == b.l / SZ) return a.r < b.r;
return a.l < b.l;
}
struct que{
int l, r, op, id;
que() {}
que(int l, int r, int op, int id):l(l), r(r), op(op), id(id) {}
};
int n, k, m, tp;
int sa[N], has[N], ql[N], qr[N];
ll s1[N], s2[N], ans[N];
vector<que> V[N];
int get(int id) {
return query(qr[id]) - query(ql[id] - 1);
}
int main() {
// freopen("input.txt", "r", stdin);
scanf("%d%d%d", &n, &k, &m);
for (int i = 1; i <= n; i++) scanf("%d", sa + i), has[i] = sa[i];
for (int i = 1; i <= m; i++) scanf("%d%d", &qu[i].l, &qu[i].r), qu[i].l++, qu[i].r++, qu[i].id = i;
sort(has + 1, has + n + 1);
tp = unique(has + 1, has + n + 1) - has - 1;
for (int i = 1; i <= n; i++) {
ql[i] = lower_bound(has + 1, has + tp + 1, sa[i] - k) - has;
qr[i] = upper_bound(has + 1, has + tp + 1, sa[i] + k) - has - 1;
sa[i] = lower_bound(has + 1, has + tp + 1, sa[i]) - has;
}
sort(qu + 1, qu + m + 1);
int l = 1, r = 0;
for (int i = 1; i <= m; i++) {
if (r < qu[i].r) {
V[l - 1].push_back(que(r + 1, qu[i].r, -1, qu[i].id));
r = qu[i].r;
}
if (l > qu[i].l) {
V[r].push_back(que(qu[i].l, l - 1, 1, qu[i].id));
l = qu[i].l;
}
if (r > qu[i].r) {
V[l - 1].push_back(que(qu[i].r + 1, r, 1, qu[i].id));
r = qu[i].r;
}
if (l < qu[i].l) {
V[r].push_back(que(l, qu[i].l - 1, -1, qu[i].id));
l = qu[i].l;
}
}
for (int i = 1; i <= n; i++) {
add(sa[i], 1);
s1[i] = s1[i - 1] + get(i);
if (i + 1 <= n) s2[i] = s2[i - 1] + get(i + 1);
for (que t : V[i]) {
for (int i = t.l; i <= t.r; i++) ans[t.id] += t.op * get(i);
}
}
l = 1, r = 0; ll res = 0;
for (int i = 1; i <= m; i++) {
res += ans[qu[i].id];
if (r < qu[i].r) {
res += s2[qu[i].r - 1] - s2[r - 1];
r = qu[i].r;
}
if (l > qu[i].l) {
res -= s1[l - 1] - s1[qu[i].l - 1];
l = qu[i].l;
}
if (r > qu[i].r) {
res -= s2[r - 1] - s2[qu[i].r - 1];
r = qu[i].r;
}
if (l < qu[i].l) {
res += s1[qu[i].l - 1] - s1[l - 1];
l = qu[i].l;
}
ans[qu[i].id] = res;
}
for (int i = 1; i <= m; i++) printf("%lld\n", ans[i]);
return 0;
}