题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6540;
数据结构的太菜了,比赛的时候没有头绪,要恶补数据结构了。。。
题意:给你一个数组,对于第i个数来说,如果存在一个位置j,使得j>i并且a[j]-k<=a[i]<=a[j]+k,那么这对数就称为好的,有q个询问,问你l到r区间有多少对好的数。
思路:离散化原序列和 原序列+k和 原序列-k,离散化需要讲这些数值排序和去重,然后莫队查询,树状数组维护;
#include<bits/stdc++.h>
#define db double
using namespace std;
const int N=27000+10;
int maxx[N*3],mini[N*3],now[N*3];
int sum[N*3],pos[N],len;
int a[N],cut,ans[N];
vector<int>vec;
struct node
{
int l,r,id;
} q[N];
bool cmp(node x,node y)
{
if(pos[x.l]==pos[y.l])
return x.r<y.r;
return pos[x.l]<pos[y.l];
}
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int v)
{
for(int i=x; i<=len; i+=lowbit(i))
sum[i]+=v;
}
int query(int x)
{
int res=0;
for(int i=x; i>0; i-=lowbit(i))
res+=sum[i];
return res;
}
int get_id(int x)//得到离散化后的值
{
return lower_bound(vec.begin(),vec.end(),x)-vec.begin()+1;
}
int main()
{
int n,k,m;
while(~scanf("%d %d %d",&n,&m,&k))
{
cut=sqrt(n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
pos[i]=i/cut;
vec.push_back(a[i]);
vec.push_back(a[i]-k);
vec.push_back(a[i]+k);
}
sort(vec.begin(),vec.end());///vectot排序
vector<int>::iterator it=unique(vec.begin(),vec.end());
vec.erase(it,vec.end());
///这两步是去重
len=vec.size();
for(int i=1; i<=n; i++)///将序列离散化
{
now[i]=get_id(a[i]);
maxx[i]=get_id(a[i]+k);
mini[i]=get_id(a[i]-k);
}
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 res=0,L=1,R=0;
for(int i=1; i<=m; i++)///莫队
{
while(R<q[i].r)
{
R++;
res+=query(maxx[R])-query(mini[R]-1);
update(now[R],1);
}
while(R>q[i].r)
{
update(now[R],-1);
res-=query(maxx[R])-query(mini[R]-1);
R--;
}
while(L<q[i].l)
{
update(now[L],-1);
res-=query(maxx[L])-query(mini[L]-1);
L++;
}
while(L>q[i].l)
{
L--;
res+=query(maxx[L])-query(mini[L]-1);
update(now[L],1);
}
ans[q[i].id]=res;
}
for(int i=1; i<=m; i++)
printf("%d\n",ans[i]);
}
return 0;
}