#cdq分治,树状数组#洛谷 5459 [BJOI2016]回转寿司

题目

[sum_{i=1}^nsum_{j=i}^{n}[Lleq sum_{k=i}^j a_kleq R] ]


分析(树状数组)

考虑前缀和,改为是否有两个数的差在([Lsim R])范围内,
显然可以用树状数组做,记录(a_i,a_i-L,a_i-R),离散化


代码(树状数组)

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
typedef long long lll;
const int N=100011;
lll a[N],b[N*3],ans;
int c[N*3],n,L,R,Tot;
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
inline void update(int x){for (;x<=Tot;x+=-x&x) ++c[x];}
inline signed query(int l,int r){
	rr int ans=0; --l;
	for (;r>l;r-=-r&r) ans+=c[r];
	for (;l>r;l-=-l&l) ans-=c[l];
	return ans;
}
signed main(){
	n=iut(),L=iut(),R=iut(),Tot=1;
	for (rr int i=1;i<=n;++i){
		a[i]=a[i-1]+iut(),b[++Tot]=a[i],
		b[++Tot]=a[i]-L,b[++Tot]=a[i]-R;
	}
	sort(b+1,b+1+Tot),Tot=unique(b+1,b+1+Tot)-b-1;
	update(lower_bound(b+1,b+1+Tot,0)-b);
	for (rr int i=1;i<=n;++i){
		rr int fi=lower_bound(b+1,b+1+Tot,a[i]-R)-b,
		       se=lower_bound(b+1,b+1+Tot,a[i]-L)-b,
			   th=lower_bound(b+1,b+1+Tot,a[i])-b;
		ans+=query(fi,se);
		update(th); 
	}
	return !printf("%lld",ans);
}

分析(cdq分治)

同理可以在cdq分治中用双指针找到(a_i-R,a_i-L)的位置,然后统计答案


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
typedef long long lll;
const int N=100011;
lll a[N],n,ans,b[N],L,R;
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
inline void cdq(int l,int r){
	if (l==r) return;
	rr int mid=(l+r)>>1;
	cdq(l,mid),cdq(mid+1,r);
	for (rr int i=mid+1,hl=l,hr=l-1;i<=r;++i){
		while (hr<mid&&a[i]-L>=a[hr+1]) ++hr;//使刚好a[hr+1]>a[i]-L
		while (hl<=mid&&a[i]-R>a[hl]) ++hl;//使a[hl]>=a[i]-R
		ans+=hr-hl+1;//为什么不会出现负数,因为首先a[i]-L>=a[i]-R,所以hr-hl>=-1,加上1正好抵消掉
	}
	rr int i1=l,j1=mid+1,tot=0;
	while (i1<=mid&&j1<=r)
	if (a[i1]<=a[j1]) b[++tot]=a[i1],++i1;
	    else b[++tot]=a[j1],++j1;
	while (i1<=mid) b[++tot]=a[i1],++i1;
	while (j1<=r) b[++tot]=a[j1],++j1;
	for (rr int i=1;i<=tot;++i) a[l+i-1]=b[i];
}
signed main(){
	n=iut(),L=iut(),R=iut();
	for (rr int i=1;i<=n;++i) a[i]=a[i-1]+iut();
	cdq(0,n);//a[0]也需要算进去
	return !printf("%lld",ans);
}
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13532969.html