【无旋treap】礼物(2022.5.28)

和洛谷上的P5459 [BJOI2016]回转寿司不能说一模一样,只能说完全相同(这题能评紫?

题目描述

1.1 题目描述

现在有一排 n 个礼物,每个礼物有一个价格 pi,不过这是一家神奇的商店,店长可能
会倒贴来出售一些礼物,也就是说价格可能为负数。
小Y 想给女朋友买礼物,为了表达心意,他希望购买的礼物总价不小于 L,但是也不能
买得太贵,因为总价大于 R 会惹女朋友生气。然而作为一个直男,小Y 确实不知道应该如
何选择,于是他想出了一个办法——选择若干紧邻连续的礼物进行购买。他现在希望知道自
己一共有多少种合适的购买方案。

1.2 输入格式

第一行为三个整数 n, L, R,含义如题意所述;
接下来一行 n 个整数,第 i 个整数为 pi,表示第 i 个礼物的价格。

1.3 输出格式

仅一行一个整数,表示满足条件的方案数。

1.4 样例输入

 5 5 8 
3 3 -2 1 3 

1.5 样例输出

4 

1.6 样例解释

依次对礼物编号为1,2,3,4,5,则满足条件的方案有 {1,2}, {1,2,3,4}, {1,2,3,4,5}, {2,3,4,5}。

1.7 数据范围与约定

对于前20%的数据满足 n≤1000;
对于另外20%的数据满足 pi 非负。
对于100%的数据满足1≤n≤100000,1≤L≤R≤109,|pi|≤100000。

解思

每次新加入一个数,要把前面所有数的前缀和都加上这个数,考虑前面不加而是将答案的区间平移,于是想到支持单点修改,区间动态查询的平衡树,FHQ无旋treap(有旋板子现在还没过2333),据说也有用树状数组离散化和CDQ分治的...

关于FHQ无旋treap参见【无旋treap hash】匹配(2022.5.21) _

平衡树代码如下:

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	int f=1,j=0;
	char w=getchar();
	while(w>'9'||w<'0'){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(w>='0'&&w<='9'){
		j=(j<<3)+(j<<1)+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=100100;
int n,L,R,now,root,ans;
int ln[N],sum[N],num[N],size[N],ls[N],rs[N],tail;
inline void update(int nown){
	size[nown]=size[ls[nown]]+size[rs[nown]]+ln[nown];
	return ;
}
void split(int nown,int &l,int &r,int val){
	if(nown==0){
		l=r=0;
		return ;
	}
	if(sum[nown]<=val)l=nown,split(rs[nown],rs[nown],r,val);
	else r=nown,split(ls[nown],l,ls[nown],val);
	update(nown);
	return ;
}
void merge(int &k,int l,int r){
	if(l==0||r==0){
		k=l+r;
		return ;
	}
	if(num[l]>num[r])k=l,merge(rs[l],rs[l],r);
	else k=r,merge(ls[r],l,ls[r]);
	update(k); 
	return ;
}
inline int newpoint(int k){
	sum[++tail]=k;
	ln[tail]=1;
	num[tail]=rand();
	return tail;
}
signed main(){
	//freopen("gift.in","r",stdin);
	//freopen("gift.out","w",stdout);
	srand(time(NULL));
	n=read();L=read();R=read();
	for(int i=1;i<=n;i++){
		int x=read(),y;
		now+=x;y=x-now;
		int l,mid=0,r;
		split(root,l,r,y);
		split(l,l,mid,y-1);
		if(mid!=0)ln[mid]++;
		else mid=newpoint(y);
		update(mid);//------------
		merge(root,l,mid);
		merge(root,root,r);
		split(root,l,r,R-now);
		split(l,l,mid,L-1-now);
		ans+=size[mid];
		merge(root,l,mid);
		merge(root,root,r);
	}
	printf("%lld",ans);
	return 0;
}
/*
5 5 8
3 3 -2 1 3
*/
posted @   flywatre  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示