HDU 6534 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

题意:

在给定一个区间中找出 |a[i]-a[j] |<=k (i<j)的对数.

思路:
首先考虑用莫队优雅暴力求解。
那么如何求解区间内对数呢?
如果暴力查找区间内符合条件的个数肯定会超时(O(n^2)) ,那么就直接查询区间内大于等于a[i]-k和小于等于a[i]+k的个数就行了。于是采用树状数组来维护每个值的个数,由于a[i]<=1e9,所以要离散化一下。每次增加和删除操作通过查询上下界,然后求出[L, R]内的和。需要注意的是上界可能会是N+1或者对应的值大于计算出的上界,所以对此要特判减1。
本以为这样就可以过了,结果还是TLE了。。。
好吧,如果每次在增加删除操作里面求上下界,会有许多重复计算,所以先预处理出每个数值的上下界及每个数对应的离散化值。终于过了。。。。。。

代码:

#include<bits/stdc++.h>
using namespace std;
const int Ms=27001;
struct node
{
    int l,r,id;
}q[Ms],FL[Ms];
int ans[Ms],T[Ms],a[Ms],b[Ms],N,k,block[Ms],res,hs[Ms];
bool cmp(node a,node b)
{
    if(block[a.l]!=block[b.l])return block[a.l]<block[b.l];
    return a.r<b.r;
}
int get_id(int x)
{
    return lower_bound(b+1,b+N+1,x)-b;
}
int lowbit(int x)
{
    return x&(-x);
}
void up(int x,int val)
{
    while(x<=N)
    {
        T[x]+=val;
        x+=lowbit(x);
    }
}
int query(int x)
{
    int re=0;
    while(x>0)
    {
        re+=T[x];
        x-=lowbit(x);
    }
    return re;
}
void add(int pos)
{
    int h=hs[pos],l=FL[h].l,r=FL[h].r;
    res+=query(r)-query(l-1);
    up(h,1);
}
void del(int pos)
{
    int h=hs[pos],l=FL[h].l,r=FL[h].r;
    up(h,-1);
    res-=query(r)-query(l-1);
}
void cake(int n)
{
    int l,r;
    for(int i=1;i<=n;i++)
    {
        hs[i]=get_id(a[i]);
        if(FL[hs[i]].l==0)
        {
            l=get_id(a[i]-k);r=get_id(a[i]+k);
            if(r==N+1)r--;
            if(b[r]>a[i]+k)r--;
            FL[hs[i]].l=l;FL[hs[i]].r=r;
        }
    }
}
int main()
{
    int n,m,unit;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    unit=sqrt(n);
    for(int i=1;i<=n;i++)block[i]=i/unit;
    sort(b+1,b+n+1);
    sort(q,q+m,cmp);
    N=unique(b+1,b+n+1)-b-1;
    int l=1,r=0;
    cake(n);
    for(int i=0;i<m;i++)
    {
        while(l<q[i].l)del(l++);
        while(l>q[i].l)add(--l);
        while(r<q[i].r)add(++r);
        while(r>q[i].r)del(r--);
        ans[q[i].id]=res;
    }
    for(int i=0;i<m;i++)printf("%d\n",ans[i]);
    return 0;
}

若有什么错误,欢迎指正^ _ ^ 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值