HDU---6534:Chika and Friendly Pairs【莫队+树状数组】

博客围绕给定长度为n的数组及m个查询展开,每次查询区间【l,r】中满足abs(Ai - Aj) <= K 的(i,j)数量。因查询可离线,采用莫队算法,用树状数组计算并维护Ai对区间的贡献,同时因数值大需先离散化,最后给出了代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

给定一个长度为n的数组,有m个查询,每次查询区间【l,r】中满足abs(Ai - Aj) <= K 的(i,j)的数量

分析:

由于查询可以离线,容易想到莫队,考虑怎么维护当前区间满足条件的(i,j)的对数,对于数值Ai的贡献:

(1)Ai > Aj,满足条件时有:Ai - Aj <= K,即:Aj >= Ai - K

(2)Ai < Aj,满足条件时有:Aj - Ai <= K,即:Aj <= Ai + K

 所以Ai对【l,r】的贡献为区间中值域为【Ai-K,Ai+K】的个数,转换为:区间中小于等于Ai+K的个数 减去 小于Ai-K的个数,正好可以用树状数组计算并维护,由于数值太大,要先离散化

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int maxn = 1e5+15;
int a[maxn],b[maxn],c[maxn],n,m,k,len,block;
struct segement{
	int l,r,id;
}s[maxn];
bool cmp(segement a,segement b){
	return a.r/block == b.r/block ? a.l < b.l : a.r < b.r;
}
LL res,tr[maxn],ans[maxn];
inline int lowbit(int x){
	return x&(-x);
}
void updata(int pos,int val){
    while(pos < len){
        tr[pos] += val;
        pos += lowbit(pos);
    }
}
LL query(int pos){
    LL res = 0;
    while(pos > 0){
        res += tr[pos];
        pos -= lowbit(pos);
    }
    return res;
}
inline void add(int x){
	int pos = lower_bound(c+1,c+len,a[x]+k) - c;
	if(c[pos] > a[x]+k) pos--;
	int q1 = query(pos);
	pos = lower_bound(c+1,c+len,a[x]-k) - c - 1;
	int q2 = query(pos);
	res += q1 - q2;
	updata(b[x],1);
}
inline void del(int x){
	int pos = lower_bound(c+1,c+len,a[x]+k) - c;
	if(c[pos] > a[x]+k) pos--;
	int q1 = query(pos);
	pos = lower_bound(c+1,c+len,a[x]-k) - c - 1;
	int q2 = query(pos);
	res = res - (q1 - q2) + 1;      //a[x]肯定在条件范围内,所以多减了要加回来
	updata(b[x],-1);
}
int main(){
	scanf("%d %d %d",&n,&m,&k);
	for(int i = 1;i <= n; ++i) {
		scanf("%d",a+i);
		c[i] = a[i];
	}
    for(int i = 0;i < m; ++i){
    	scanf("%d %d",&s[i].l,&s[i].r);
    	s[i].id = i;
    }
    block = sqrt(n*1.0);
    sort(s,s+m,cmp);
    sort(c+1,c+n+1);
    len = unique(c+1,c+n+1) - c;
    c[len] = 2e9;
    for(int i = 1;i <= n; ++i) b[i] = lower_bound(c+1,c+len,a[i]) - c;  //离散化
    int L = 1, R = 0;
    for(int i = 0;i < m; ++i){
		while(R < s[i].r) ++R,add(R);
    	while(R > s[i].r) del(R),--R;
    	while(L < s[i].l) del(L),++L;
        while(L > s[i].l) --L,add(L);
    	ans[s[i].id] = res;
    }
    for(int i = 0;i < m; ++i) printf("%lld\n",ans[i]);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值