Problem Description
Chika gives you an integer sequence a1,a2,…,an and m tasks. For each task, you need to answer the number of “friendly pairs” in a given interval.
friendly pair: for two integers ai and aj, if i<j and the absolute value of ai−aj is no more than a given constant integer K, then (i,j) is called a “friendly pair”.A friendly pair (i,j) in a interval [L,R] should satisfy L≤i<j≤R.
Input
The first line contains 3 integers n (1≤n≤27000), m (1≤m≤27000) and K (1≤K≤109), representing the number of integers in the sequence a, the number of tasks and the given constant integer.
The second line contains n non-negative integers, representing the integers in the sequence a. Every integer of sequence a is no more than 109.
Then m lines follow, each of which contains two integers L, R (1≤L≤R≤n). The meaning is to ask the number of “friendly pairs” in the interval [L,R]。
Output
For each task, you need to print one line, including only one integer, representing the number of “friendly pairs” in the query interval.
Sample Input
7 5 3
2 5 7 5 1 5 6
6 6
1 3
4 6
2 4
3 4
Sample Output
0
2
1
3
1
题目大意:Chika有n个数,然后问我们在区间[L,R]中有多少对[i,j]是满足i<j且ai-aj的绝对值是不大于给出的k的条件。
解题思路:我们可以知道如果加入一个数,那么加入这个数之后对答案的贡献是现有多少个数是在[x-k,x+k]中的,同样的,删除一个数之后答案的该变量也是一样的,所以我们可以用树状数组来维护这个前缀和,那么这个区间的数的个数就是ask(x+k)-ask(k-k-1)啦,当然,因为这里的数的范围是1e9,所以需要离散化,那么现在我们知道加入一个数和删除一个数之后对答案的贡献,我们就可以莫队啦。离线求出所有查询的答案就可以啦。这里还有一个坑,就是lower_bound和upper_bound操作不能再加入时用,需要需处理出可加入某个数或删除某个数时能够影响到答案的区间,不然会T到飞起别问我怎么知道的,呜呜呜。
代码:
#pragma GCC optimize(2)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <bitset>
#include <queue>
//#include <random>
#include <time.h>
using namespace std;
#define int long long
#define ls root<<1
#define rs root<<1|1
const int maxn = 1e5+7;
const int inf = 0x3f3f3f3f;
//std::mt19937 rnd(233);
struct query{
int l, r, id, pos;
bool operator <(query a)const{
return pos == a.pos ? (pos&1?r<a.r:r>a.r) : pos < a.pos;
}
} q[maxn];
int sum[maxn], n, a[maxn], b[maxn], m, k, len, pos[maxn];
int up[maxn], low[maxn];
void add(int x,int d)
{
if(!x)
return;
while(x<=n){
sum[x] += d;
x += (x & -x);
}
}
int ask(int x)
{
int ans = 0;
while(x){
ans += sum[x];
x -= (x & -x);
}
return ans;
}
int res;
void add(int x)
{
int l = low[x], r = up[x];
res += ask(r) - ask(l - 1);
add(a[x], 1);
}
void del(int x)
{
int l = low[x], r = up[x];
add(a[x], -1);
res -= ask(r) - ask(l - 1);
}
int ans[maxn];
signed main()
{
#ifndef ONLINE_JUDGE
//freopen("in.in", "r", stdin);
//freopen("out.out", "w", stdout);
#endif
scanf("%lld%lld%lld", &n, &m, &k);
int len1 = sqrt(n);
for (int i = 1; i <= n;i++){
scanf("%lld", a + i);
b[i] = a[i];
}
sort(b + 1, b + 1 + n);
len = unique(b + 1, b + 1 + n) - b - 1;
for (int i = 1; i <= n;i++){
low[i] = lower_bound(b + 1, b + len + 1, a[i] - k) - b;//现预处理加入这个数时能够对答案有影响的区间
up[i] = upper_bound(b + 1, b + 1 + len, a[i] + k) - b - 1;
a[i] = lower_bound(b + 1, b + 1 + len, a[i]) - b;//预处理出这个数所在b数组中的位置
}
for (int i = 1; i <= m;i++){
scanf("%lld%lld", &q[i].l, &q[i].r);
q[i].id = i, q[i].pos = (q[i].l - 1) / len1 + 1;
}
sort(q + 1, q + 1 + m);
int l = 1, r = 0;
for (int i = 1; i <= m;i++){
while(r<q[i].r){
add(++r);
}
while(r>q[i].r){
del(r--);
}
while(l<q[i].l){
del(l++);
}
while(l>q[i].l){
add(--l);
}
ans[q[i].id] = res;
}
for (int i = 1; i <= m;i++){
printf("%lld\n", ans[i]);
}
}