2019CCPC湖南全国邀请赛(广东省赛、江苏省赛) Chika and Friendly Pairs 莫队+离散化+树状数组

Chika and Friendly Pairs

题目链接

  • 时间:1000ms
  • 内存:524288K

题意:有一个大小为m的序列a,对于任意两个元素ai和aj,如果他们的差的绝对值小于等于k,我们定义其为“友好对”。现在给出n个询问[L,R],问在区间[L,R]之间有多少个“友好对”。

分析:
首先这个题只涉及区间询问,没有涉及区间修改,可以考虑用莫队进行区间暴力。
假设已知一个区间内的答案为s,那么新加入一个元素x时,可以看在原有区间中处在[x-k,x+k]之间的元素有多少个,更新s,删除一个元素时类似。而查询区间元素可以用树状数组维护,记录某个值的数的个数。
由于数的取值很大,需要进行离散化处理,缩小值域。
注意因为考虑到x±k的值,离散化时要将x,x+k,x-k均加入到离散化的数组中去。

AC代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
#define lowbit(x) x&(-x)
typedef long long ll;
const int maxn = 27007;

int a[maxn],X[maxn*3];
ll c[maxn*4],ans[maxn],s=0;
int bloc;
int m,n,k,xcnt=0;
struct Node
{
    int key,l,r;
}mapp[maxn];
struct Query
{
    int l,r,id,bl;
    Query(){}
    Query(int l,int r,int id):l(l),r(r),id(id){bl=(l-1)/bloc+1;}
    bool operator<(const Query &rsh)
    {
        if(bl==rsh.bl) return r < rsh.r;
        return bl < rsh.bl;
    }
}queries[maxn];
ll sum(int endd)
{
    ll ssum = 0;
    while(endd>0)
    {
        ssum+=c[endd];
        endd-=lowbit(endd);
    }
    return ssum;
}
int binX(int key,int n)
{
    int pos = lower_bound(X,X+n,key)-X;
    return pos == n ? -1:pos;
}
void update(int pos,int delta)
{
    while(pos<=xcnt)
    {
        c[pos]+=delta;
        pos+=lowbit(pos);
    }
}

void insert(int pos)
{
    s+=sum(mapp[pos].r)-sum(mapp[pos].l-1);
    update(mapp[pos].key,1);
}
void erase(int pos)
{
    update(mapp[pos].key,-1);
    s-=sum(mapp[pos].r)-sum(mapp[pos].l-1);
}
void solve()
{
    int L=1,R=0;
    s=0;
    for(int i = 1; i <= m; ++i)
    {
        Query &qi = queries[i];
        while(R<qi.r) insert(++R);
        while(L>qi.l) insert(--L);
        while(R>qi.r) erase(R--);
        while(L<qi.l) erase(L++);
        ans[qi.id]=s;
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    bloc = sqrt(n+0.5);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d",&a[i]);
        X[xcnt++]=a[i];
        X[xcnt++]=a[i]-k;
        X[xcnt++]=a[i]+k;
    }
    for(int i = 1; i <= m; ++i)
    {
        int tl,tr;
        scanf("%d%d",&tl,&tr);
        queries[i]=Query(tl,tr,i);
    }
    sort(X,X+xcnt);
    xcnt = unique(X,X+xcnt)-X;
    for(int i = 1; i <= n; ++i)
    {
        mapp[i].key=binX(a[i],xcnt);
        mapp[i].l=binX(a[i]-k,xcnt);
        mapp[i].r=binX(a[i]+k,xcnt);
    }
    sort(queries+1,queries+1+m);
    solve();
    for(int i = 1; i <= m; ++i)
        printf("%lld\n",ans[i]);
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值