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

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章