HDU-6534-Chika and Friendly Pairs

2019CCPC湘潭邀请赛的C题
大小为n的数组,m次查询,查询区间[l,r]内大小差距不超过k的数对的个数,可离线。m范围[1,27000],n范围[1,27000]

这是一道分块+莫队+树状数组的题目
将使用分块降低莫队复杂度为 O ( n ) O(\sqrt n) O(n ),用莫队+树状数组维护当前区间的答案,树状数组维护的是当前区间内每个数的数量,增加区间每加入一个数x,结果增加当前区间内[x-k,x+k]的数的个数并在树状数组中这个数的数量加一;减小区间时每去掉一个数x,树状数组中这个数的数量减一,结果减少当前区间内[x-k,x+k]的数的个数。
写错的地方:
莫队初始状态:l=1,r=0,不是l=0,r=0
树状数组的下标为离散化后每个数的位置,第i个数a[i]的位置是mid[i],a[i]+k的位置是up[maxn],a[i]-k的位置是down[maxn]。

复杂度 O ( m n l o g ( n ) ) O(m\sqrt nlog(n)) O(mn log(n))

#include<bits/stdc++.h>
#define lowbit(x) x&(-x)
#define de(x) cout<<#x<<" = "<<x<<endl;
using namespace std;
typedef long long ll;
const ll maxn=1e5+10;

ll Tree[maxn];//树状数组
ll a[maxn];
ll b[maxn];//离散化
ll be[maxn];//分块
ll up[maxn],mid[maxn],down[maxn];//a[i]-k,a[i],a[i]+k排序并离散化后在b中的左标
ll ans[maxn];

void update(ll x,ll val){
    while(x<maxn){
        Tree[x]+=val;
        x+=lowbit(x);
    }
}

ll query(ll x){
    ll sum=0;
    while(x>0){
        sum+=Tree[x];
        x-=lowbit(x);
    }
    return sum;
}

struct Q{
    ll l,r,id;
    friend bool operator <(Q x,Q y){
        return be[x.l]==be[y.l]?x.r<y.r:x.l<y.l;
    }
}q[maxn];

int main(){
    ll n,m,k;
    scanf("%lld%lld%lld",&n,&m,&k);
    ll tot=0;
    ll sz=sqrt(n);
    for(ll i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        b[++tot]=a[i]-k;
        b[++tot]=a[i];
        b[++tot]=a[i]+k;
        be[i]=i/sz;
    }
    sort(b+1,b+1+tot);
    ll num=unique(b+1,b+1+tot)-b-1;
    for(ll i=1;i<=n;i++){
        down[i]=lower_bound(b+1,b+1+num,a[i]-k)-b;
        mid[i]=lower_bound(b+1,b+1+num,a[i])-b;
        up[i]=lower_bound(b+1,b+1+num,a[i]+k)-b;
    }

    for(ll i=1;i<=m;i++){
        scanf("%lld%lld",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+1+m);
    ll l=1,r=0,res=0;
    for(ll i=1;i<=m;i++){
        while(r<q[i].r){
            r++;
            res+=query(up[r])-query(down[r]-1);
            update(mid[r],1);
        }
        while(r>q[i].r){
            update(mid[r],-1);
            res-=query(up[r])-query(down[r]-1);
            r--;
        }
        while(l>q[i].l){
            l--;
            res+=query(up[l])-query(down[l]-1);
            update(mid[l],1);
        }
        while(l<q[i].l){
            update(mid[l],-1);
            res-=query(up[l])-query(down[l]-1);
            l++;
        }
        ans[q[i].id]=res;
    }
    for(ll i=1;i<=m;i++){
        printf("%lld\n",ans[i]);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值