luogu P5677 [GZOI2017]配对统计 |离线树状数组

题目描述

给定n个数a1,⋯ ,an。

对于一组配对(x,y),若对于所有的i=1,2,⋯ ,n,满足∣ax−ay∣≤∣ax−ai∣(i≠x),则称(x,y)为一组好的配对(|x|表示x的绝对值)。

给出若干询问,每次询问区间[l,r]中含有多少组好的配对。

即,取x,y(l≤x,y≤r),问有多少组(x,y)是好的配对。

输入格式

第一行两个正整数n,m。

第二行n个数a1,⋯ ,an​。

接下来m行,每行给出两个数l,r。

输出格式

Ansi​表示第i次询问的答案,输出 即可。


预处理配对

利用树状数组查找数量

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=3e5+10;
#define int long long
int n,m;
vector<int>p[N],p1[N],p2[N];
struct node{
	int val,id;
}a[N];
inline bool cmp(node t1,node t2){
	return t1.val<t2.val;
}
int c[N];
inline void add(int x,int y){
	for(;x<=n;x+=x&(-x))c[x]+=y;
}

inline int sum(int x){
	int res=0;
	for(;x;x-=x&(-x))res+=c[x];
	return res;
}
int ans[N];
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)scanf("%lld",&a[i].val),a[i].id=i;
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++){
		int Min=(1<<30);
		if(i!=1)Min=min(Min,a[i].val-a[i-1].val);
		if(i!=n)Min=min(Min,a[i+1].val-a[i].val);
		if(i!=1&&a[i].val-a[i-1].val==Min)
		p[min(a[i].id,a[i-1].id)].push_back(max(a[i].id,a[i-1].id));
		if(i!=n&&a[i+1].val-a[i].val==Min)
		p[min(a[i].id,a[i+1].id)].push_back(max(a[i].id,a[i+1].id));
	}
	for(int i=1,l,r;i<=m;i++){
		scanf("%lld%lld",&l,&r);
		p1[l].push_back(r);
		p2[l].push_back(i);
	}
	for(int i=n;i>=1;i--){
		for(int j=0;j<p[i].size();j++)add(p[i][j],1);
		for(int j=0;j<p1[i].size();j++)ans[p2[i][j]]=sum(p1[i][j]);
	}
	int sum=0;
	for(int i=1;i<=m;i++)sum+=ans[i]*i;
	printf("%lld\n",sum);
}

猜你喜欢

转载自www.cnblogs.com/naruto-mzx/p/12666796.html
今日推荐