HDU6534 Chika and Friendly Pairs(树状数组+离散化+莫队)

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
题意:给出n个数(用数组a存储),和m组询问区间(L,R),还有一个K,对于每一组询问,给出这个区间中满足(a[i] - a[j])的绝对值不大于K的数对的个数,其中i<j;
思路:挂在莫队的标签上就用莫队咯,但是问题就来了,怎么在区间指针lp,rp转移的时候维护好答案,第一想法便是如果能够在指针转移的时候,我们假设要加入或者移除一个x,只要找出此时区间中和x满足题意的数的个数那么就很好办,直接维护答案就Ok,然后这个问题就和hdu6621有点像了,写主席树来查询一下也就行了,时间复杂度的话,主席树不是log(n)吗,然后我看的一篇莫队论文里面说维护时间尽量O(1),数据弱的时候log(n)跑问题也不大,那就写吧。然后就T了(T^T)。。。而且T得还挺严重的,改了分快的数量都不行.然后看了下题解都是树状数组+莫队过的,还说啥卡常,只能这样做(我吐了,难道主席树+莫队它不香,但是树状数组+莫队代码短是真的香)
但是你以为就这¿对于一个x,要找到对应区间中[x-k,x+k]的数的数量,我们找到x-k,x+k对应离散的区间,并且对于每一个数都要预处理一下,不能再莫队的修改中再lower_bound找,我反正就在这儿一直T

#include<bits/stdc++.h>
#include <cmath>
#include <algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (1000000007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef long double ld;
const int inf_max = 0x3f3f3f;
const ll Linf = 9e18;
const int maxn = 3e4+10;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
struct QRY
{
    int l,r,id;
    ll ans;
}q[maxn];
const int up = 30000;
int n,m,k,cnt,a[maxn],lsan[maxn],tot,tree[maxn],block,lp,rp,le[maxn],ri[maxn];
ll ret;
inline bool cmp1(QRY a,QRY b) {
    int belonga = (a.l - 1) / block + 1,belongb = (b.l - 1) / block + 1;
    return (belonga == belongb ? a.r < b.r : a.l < b.l);
}
inline bool cmp2(QRY a,QRY b) {
    return a.id < b.id;
}
inline int getpos(int x) {
    return lower_bound(lsan + 1,lsan + 1 + tot,x) - lsan;
}
inline void update(int pos,int val) {
    if(!pos) return ;
    while(pos <= up) {
        tree[pos] += val;
        pos += lowbit(pos);
    }
}
inline ll query(int x) {
    ll res = 0;
    while(x > 0) {
        res += tree[x];
        x -= lowbit(x);
    }
    return res;
}
inline void myremove(int x) {
    update(getpos(x),-1);  //我们要先删除这个数再找  否则就会把自己也算进去。造成多算
    ret -= query(ri[x]) - query(le[x] - 1);
}
inline void add(int x) {
    ret += query(ri[x]) - query(le[x] - 1);
    update(getpos(x),1);  //同理,要先找了再加不然也会多算。
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i = 1; i <= n; ++i) {
        a[i] = read();
        lsan[i] = a[i];
    }
    //离散
    sort(lsan + 1,lsan + 1 + n);
    tot = unique(lsan + 1,lsan + 1 + n) - lsan -1;
    // 分块处理
    block = (int)sqrt(n * 2);
    for(int i = 1;i <= n;++i) {
        le[a[i]] = lower_bound(lsan + 1,lsan + 1 + tot,a[i] - k) - lsan;
        ri[a[i]] = upper_bound(lsan + 1,lsan + 1 + tot,a[i] + k) - lsan - 1;
    }  //预处理一下对于每个数x[x-k,x+k]对应的离散化区间。
    for(int i = 1;i <= m; ++i) {
        q[i].l = read();q[i].r = read();
        q[i].id = i;
    }
    sort(q + 1,q + 1 + m,cmp1);
    // 莫队处理询问
    lp = 1;rp = 0;
    for(int i = 1;i <= m; ++i) {
        if(q[i].l == q[i].r) {
            q[i].ans = 0;
            continue;
        }
        while(lp < q[i].l) myremove(a[lp]),++lp;
        while(lp > q[i].l) --lp,add(a[lp]);
        while(rp > q[i].r) myremove(a[rp]),--rp;
        while(rp < q[i].r) ++rp,add(a[rp]);
        q[i].ans = ret;
    }
    sort(q + 1,q + 1 + m,cmp2);
    for(int i = 1;i <= m; ++i) {
        printf("%lld\n",q[i].ans);
    }
    return 0;
}
发布了33 篇原创文章 · 获赞 14 · 访问量 409

猜你喜欢

转载自blog.csdn.net/qq_44077455/article/details/104022179