HDU - 6534 Chika and Friendly Pairs

 这个题其实也是很简单的莫队,题目要求是给一个序列,询问l-r区间内部,找到有多少对答案满足 i < j 并且

| a[ i ] -a[ j ] | <=k 也就是有多少对,满足差值小于k的个数。

把这个式子展开,其实就是-k<= a[ i ] -a [ j ] <= k 也就是  a[ j ] -k <= a[ i ] <= a[ j ] + k,也就是说,对于某个 j 位置,我们需要在询问的区间内,找到 i < j 并且在[ a[j] -k ,a[j] +k ] 范围中的数的个数,这个其实可以通过树状数组区间查询即可。

但是对于k来说,太大了,树状数组也开不下,所以我们要进行离散化,把a[i],a[i]+k,a[i]-k位置存下来即可(老套路了)保证每个位置都能找得到,然后区间查询即可,然后每次算贡献即可。

  

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxx = 2e5+6;
int block;
int a[maxx];
std::vector<int>vx;
int sum[maxx];
int ans[maxx];
int num;
int n,m,k;
struct node{
  int l,r;
  int id;
  friend bool operator < (const node &a,const node &b){
      if(a.l/block==b.l/block){
          return a.r<b.r;
      }
      return a.l/block<b.l/block;
  }
}q[maxx];
int low[maxx];
int up[maxx];
int p[maxx];
int lowbit(int x){
  return x&(-x);
}
void add(int x,int w){
   for(int i=x;i<=3*n;i+=lowbit(i)){
     sum[i]+=w;
   }
   return ;
}
int getsum(int x){
   int s=0;
   for(int i=x;i;i-=lowbit(i)){
       s+=sum[i];
   }
   return s;
}
void add(int x){
   num+=getsum(up[x])-getsum(low[x]-1);
   add(p[x],1);
}
void del(int x){
   add(p[x],-1);
   num-=getsum(up[x])-getsum(low[x]-1);
}
int main(){
  while(~scanf("%d%d%d",&n,&m,&k)){
     block=sqrt(n);
     memset(sum,0,sizeof(sum));
     memset(ans,0,sizeof(ans));
     vx.clear();
     ///绝对值小于等于K
     for (int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        vx.push_back(a[i]);
        vx.push_back(a[i]+k);
        vx.push_back(a[i]-k);
     }
     num=0;
     sort(vx.begin(),vx.end());
     vx.erase(unique(vx.begin(),vx.end()),vx.end());
     int sz=vx.size();
     for(int i=1;i<=n;i++){
        p[i]=lower_bound(vx.begin(),vx.end(),a[i])-vx.begin()+1;
        low[i]=lower_bound(vx.begin(),vx.end(),a[i]-k)-vx.begin()+1;
        up[i]=lower_bound(vx.begin(),vx.end(),a[i]+k)-vx.begin()+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);
     int l=1,r=0;
     num=0;
     for(int i=1;i<=m;i++){
        while(l<q[i].l)del(l),l++;
      //  cout<<num<<" ";
        while(l>q[i].l)l--,add(l);
      //  cout<<num<<" ";
        while(r<q[i].r)r++,add(r);
       // cout<<num<<" ";
        while(r>q[i].r)del(r),r--;
      //  cout<<num<<" "<<endl;
        ans[q[i].id]=num;
     }
    for(int i=1;i<=m;i++){
        printf("%d\n",ans[i]);
    }
  }
  return 0;
}

 

上一篇:集训小模拟赛2


下一篇:暴力+组合数学+预处理+双指针——cf 1371E1+E2