#树状数组#洛谷 5677 [GZOI2017]配对统计

题目


分析

考虑处理出所有右端点的能够匹配的左端点,然后用树状数组离线查询


代码

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#define rr register
using namespace std;
const int N=300011; vector<int>K[N];
struct rec{int w,rk;}a[N];
struct three{int l,r,rk;}q[N];
int c[N],n,m,ans[N]; long long Ans;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans; 
}
inline void update(int x,int y){
	for (;x<=n;x+=-x&x) c[x]+=y;
}
inline signed query(int x){
	rr int ans=0;
	for (;x;x-=-x&x) ans+=c[x];
	return ans;
}
inline void add(int x,int y){
	if (x>y) x^=y,y^=x,x^=y;
	K[y].push_back(x);
}
bool cmp1(rec x,rec y){return x.w<y.w;}
bool cmp2(three x,three y){return x.r<y.r;}
signed main(){
	n=iut(); m=iut();
	for (rr int i=1;i<=n;++i)
	    a[i]=(rec){iut(),i};
	sort(a+1,a+1+n,cmp1);
	for (rr int i=1;i<=n;++i){
		rr int t=2e9;
		if (i>1&&a[i].w-a[i-1].w<t) t=a[i].w-a[i-1].w;
		if (i<n&&a[i+1].w-a[i].w<t) t=a[i+1].w-a[i].w;
		if (i>1&&a[i].w-a[i-1].w==t) add(a[i].rk,a[i-1].rk);
		if (i<n&&a[i+1].w-a[i].w==t) add(a[i].rk,a[i+1].rk);
	}
	for (rr int i=1;i<=m;++i) q[i]=(three){iut(),iut(),i};
	sort(q+1,q+1+m,cmp2);
	for (rr int i=1,j=1;i<=m;++i){
		for (;j<=q[i].r;++j){
			rr int len=K[j].size();
			for (rr int o=0;o<len;++o)
			    update(K[j][o],1);
		}
		ans[q[i].rk]=query(q[i].r)-query(q[i].l-1);
	}
	for (rr int i=1;i<=m;++i) Ans+=1ll*ans[i]*i;
	return !printf("%lld",Ans);
}
posted @ 2020-11-03 20:48  lemondinosaur  阅读(82)  评论(0编辑  收藏  举报