啊哈哈哈这道题我现场就没做出来,当时直觉是莫队但是敲不出来
题目:http://acm.hdu.edu.cn/showproblem.php?pid=6534
首先看题面很容易让人联想到莫队
然后看k的数据量 1e9 再看n的数据量 25000 ,于是就想到离散化
关键就在于如何短时间进行L,R区间的递推
在一个区间中查找大小为 x-k 到 x+k 的数量有多少个,可以转化为 查询大小小于x-k 的 和大小小于 x+k 的,然后两者做差
对于此题,可以使用树状数组在logn的时间递推
计算复杂度:
莫队 n^(2/3) * 树状数组 logN n数据量25000,可以过
#include<bits/stdc++.h>
using namespace std;
const int maxn = 27007;
int num[maxn], b[maxn], rk[maxn];
int tree[maxn], C[maxn];
int belong[maxn], ans[maxn];
struct node {
int l, r, id;
}q[maxn];
int n, m, k, len;
bool cmp(node a, node b) {
return belong[a.l] ^ belong[b.l] ? belong[a.l] < belong[b.l] : (belong[a.l] & 1 ? a.r < b.r : a.r > b.r);
}
int lowbit(int t) {
return t & (-t);
}
int getsum(int x) {
int ans = 0;
for (int i = x; i > 0; i -= lowbit(i)) ans += C[i];
return ans;
}
void add(int x, int y) {
for (int i = x; i <= n; i += lowbit(i)) C[i] += y;
}
int add(int x) { //放下标
int t1 = num[x] - k, t2 = num[x] + k;
t1 = lower_bound(b + 1, b + 1 + len, t1) - b;
t2 = upper_bound(b + 1, b + 1 + len, t2) - b - 1;
int ret = getsum(t2) - getsum(t1 - 1);
add(rk[x], 1); //注意先后位置
return ret;
}
int del(int x) {
int t1 = num[x] - k, t2 = num[x] + k;
t1 = lower_bound(b + 1, b + 1 + len, t1) - b;
t2 = upper_bound(b + 1, b + 1 + len, t2) - b - 1;
add(rk[x], -1);
return getsum(t1 - 1) - getsum(t2);
}
int main() {
cin >> n >> m >> k;
double siz = sqrt(1.0*n);
for (int i = 1; i <= n; i++) {
scanf("%d", num + i);
b[i] = num[i];
belong[i] = ceil(i / siz);
}
sort(b + 1, b + 1 + n);
len = unique(b + 1, b + 1 + n) - (b + 1);
for (int i = 1; i <= n; i++) {
rk[i] = lower_bound(b + 1, b + 1 + len, num[i]) - b;
}
for (int i = 1; i <= m; i++) {
scanf("%d %d", &q[i].l, &q[i].r);
q[i].id = i;
}
sort(q + 1, q + m + 1, cmp);
int l = 1, r = 0, sto = 0;
for (int i = 1; i <= m; i++) {
while (l < q[i].l) sto += del(l++);
while (l > q[i].l) sto += add(--l);
while (r < q[i].r) sto += add(++r);
while (r > q[i].r) sto += del(r--);
ans[q[i].id] = sto;
}
for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}