1. 程式人生 > 其它 >【無旋treap】禮物(2022.5.28)

【無旋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
*/