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