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

26 篇文章 0 订阅
7 篇文章 0 订阅

This way

题意:

给你一个数组,对于第i个数来说,如果存在一个位置j,使得j>i并且a[j]-k<=a[i]<=a[j]+k,那么这对数就称为好的,有q个询问,问你l到r区间有多少对好的数。

题解:

有点像上次那道区间因子对数的题目,但是这道题不能用那种方法做,因为如果要维护消去前面的数影响后面数的位置的话,有可能是n*n的复杂度。但是可以用用莫队+树状数组做,离散化a[i]和a[i]+k和a[i]-k-1即可。

#include<bits/stdc++.h>
using namespace std;
const int N=27005;
int num[N*3];
int lowbit(int x)
{
    return x&(-x);
}
void add(int x,int val)
{
    for(int i=x;i<N*3;i+=lowbit(i))
        num[i]+=val;
}
int query(int x)
{
    int ans=0;
    for(int i=x;i;i-=lowbit(i))
        ans+=num[i];
    return ans;
}
int a[N],b[N*3],upa[N],downa[N];
struct node
{
    int l,r,id;
}q[N];
int pos[N],ans[N];
bool cmp(node x,node y)
{
    return pos[x.l]<pos[y.l]||pos[x.l]==pos[y.l]&&x.r<y.r;
}
int main()
{
    int n,m,k,all=0;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),b[++all]=a[i],b[++all]=a[i]-k-1,b[++all]=a[i]+k;
    sort(b+1,b+1+all);
    all=unique(b+1,b+1+all)-b-1;
    for(int i=1;i<=n;i++)
        upa[i]=lower_bound(b+1,b+1+all,a[i]+k)-b,downa[i]=lower_bound(b+1,b+1+all,a[i]-k-1)-b,a[i]=lower_bound(b+1,b+1+all,a[i])-b;
    int blog=sqrt(n);
    for(int i=1;i<=n;i++)
        pos[i]=(i-1)/blog+1;
    for(int i=1;i<=m;i++)
        scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
    sort(q+1,q+1+m,cmp);
    int l=q[1].l,r=q[1].l-1,sum=0;
    for(int i=1;i<=m;i++)
    {
        while(r<q[i].r)
        {
            r++;
            sum+=query(upa[r])-query(downa[r]);
            add(a[r],1);
        }
        while(l>q[i].l)
        {
            l--;
            sum+=query(upa[l])-query(downa[l]);
            add(a[l],1);
        }
        while(r>q[i].r)
        {
            add(a[r],-1);
            sum-=query(upa[r])-query(downa[r]);
            r--;
        }
        while(l<q[i].l)
        {
            add(a[l],-1);
            sum-=query(upa[l])-query(downa[l]);
            l++;
        }
        ans[q[i].id]=sum;
    }
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值