题目链接
题意:
成为一个配对需要的条件是两个数在数组中的差值的绝对值最小,给你一个区间,求区间内一共有多少对配对。
思路:
首先排序处理原数组,然后在相邻位置找配对,再将找好的配对排序,将位置信息保留,放入树状数组中,查询区间内有多少配对的位置在查询范围内即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e6+7;
const int mod=1e9+7;
const int inf=0x7fffffff;
const double pi=3.1415926535;
int n,m,tot;
int tree[N],ans[N];
struct shuzu
{
int num,place;
}sz[N];
struct ask
{
int l,r,place;
}a[N];
struct peidui
{
int l,r;
}pd[N];
bool cmp1(shuzu x,shuzu y)
{
return x.num<y.num;
}
bool cmp2(ask x,ask y)
{
return x.l<y.l;
}
bool cmp3(peidui x,peidui y)
{
return x.l<y.l;
}
int lowbit(int x)
{
return x&-x;
}
void add(int x,int y)
{
while(x<=tot)
{
tree[x]+=y;
x+=lowbit(x);
}
}
int get(int x)
{
int tmp=0;
while(x)
{
tmp+=tree[x];
x-=lowbit(x);
}
return tmp;
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>sz[i].num;
sz[i].place=i;
}
sort(sz+1,sz+n+1,cmp1);
sz[0].num=sz[n+1].num=1<<30;
for(int i=1;i<=n;i++)
{
if(abs(sz[i].num-sz[i-1].num)==abs(sz[i].num-sz[i+1].num))
{
pd[++tot].l=min(sz[i].place,sz[i-1].place);
pd[tot].r=max(sz[i].place,sz[i-1].place);
pd[++tot].l=min(sz[i].place,sz[i+1].place);
pd[tot].r=max(sz[i].place,sz[i+1].place);
}
if(abs(sz[i].num-sz[i-1].num)<abs(sz[i].num-sz[i+1].num))
{
pd[++tot].l=min(sz[i].place,sz[i-1].place);
pd[tot].r=max(sz[i].place,sz[i-1].place);
}
if(abs(sz[i].num-sz[i-1].num)>abs(sz[i].num-sz[i+1].num))
{
pd[++tot].l=min(sz[i].place,sz[i+1].place);
pd[tot].r=max(sz[i].place,sz[i+1].place);
}
}
sort(pd+1,pd+tot+1,cmp3);
for(int i=1;i<=m;i++)
{
cin>>a[i].l>>a[i].r;
a[i].place=i;
}
sort(a+1,a+m+1,cmp2);
int tmp=tot;
for(int i=m;i>=1;i--)
{
while(pd[tmp].l>=a[i].l)
{
add(pd[tmp].r,1);
tmp--;
}
ans[a[i].place]=get(a[i].r);
}
int last=0;
for(int i=1;i<=m;i++)
{
last+=ans[i]*i;
}
cout<<last<<endl;
return 0;
}