题目链接
题意:
给你一个序列,m次询问区间 [L,R] 内 i<j且 |ai-aj|<=k的友好对数的个数。
思路:
莫队+离散化+树状数组
将序列元素+k,-k,和原本的值保存在一个数组中,由于序列元素很大,需离散化处理;将询问区间存储,离线状态下用莫队进行查询;不断插入、删除元素,用树状数组(用树状数组保存比较简单)求满足条件的区间元素个数并不断更新树状数组,逐个求得区间答案。
code:
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#define debug(x) cout << #x << ":" << x << endl;
#define bug cout << "********" << endl;
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define fi first
#define se second
using namespace std;
typedef long long ll;
const double eps = 1e-10;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double pi = acos(-1.0);
const int mod = 1e9 + 7;
const int maxn = 3e4 + 10;
int len,sum[maxn<<2],n,m,k;
int s[maxn],p[maxn<<2],block,ans[maxn];
int minn[maxn],maxx[maxn],r[maxn];//离散后的序列号
struct node
{
int l,r,id;
bool operator<(const node &a){
return l/block==a.l/block ? r<a.r : l<a.l;
}
}t[maxn];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int b)
{//更新
while(x<=len){
sum[x]+=b;
x+=lowbit(x);
}
}
int query(int x)
{//区间求和
int ret=0;
while(x){
ret+=sum[x];
x-=lowbit(x);
}
return ret;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
int tot=0;
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
p[++tot]=s[i]-k,p[++tot]=s[i]+k,p[++tot]=s[i];//保存s[i]+k、s[i]-k、s[i]的值
}
block=sqrt(n);
for(int i=1;i<=m;i++){
scanf("%d%d",&t[i].l,&t[i].r);
t[i].id=i;
}
sort(p+1,p+tot+1);
len=unique(p+1,p+tot+1)-p;//数组去重离散化
for(int i=1;i<=n;i++){//离散化后得到的相应序号
r[i]=lower_bound(p+1,p+len+1,s[i])-p;
minn[i]=lower_bound(p+1,p+len+1,s[i]-k)-p;
maxx[i]=lower_bound(p+1,p+len+1,s[i]+k)-p;
}
sort(t+1,t+m+1);
int L=1,R=0,ret=0;
//莫队算法
for(int i=1;i<=m;i++){
while(t[i].l<L){
L--;//如果要插入元素,先查询区间和,再更新树状数组
ret+=query(maxx[L])-query(minn[L]-1);
update(r[L],1);
}
while(t[i].l>L){
update(r[L],-1);//如果要删除元素,先更新树状数组,再求区间和,下面的原理一样
ret-=query(maxx[L])-query(minn[L]-1);
L++;
}
while(t[i].r>R){
R++;
ret+=query(maxx[R])-query(minn[R]-1);
update(r[R],1);
}
while(t[i].r<R){
update(r[R],-1);
ret-=query(maxx[R])-query(minn[R]-1);
R--;
}
//离线状态下保存对应区间的友好对数个数
ans[t[i].id]=ret;
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}