HDU-6534 (莫队算法+树状数组)

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]);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值