1. 程式人生 > 實用技巧 >CF1440E Greedy Shopping(有技巧的線段樹)

CF1440E Greedy Shopping(有技巧的線段樹)

給您一個整數陣列a1,a2,…,an。該陣列不增加。

讓我們考慮一條有n個商店的生產線。商店用從1到n的整數從左到右編號。在第i家商店中,一頓飯的費用等於ai。

您應該處理兩種型別的q查詢:

1 x y:對於每個車間1≤i≤x,設定ai = max(ai,y)。
2 x y:讓我們考慮一個擁有y錢的飢餓的人。他參觀了從第x家到第n家的商店,如果他能在當前的商店買一頓飯,他就購買其中一件。查詢他將購買多少餐。如果他有至少ai錢,該人可以在商店i中買一頓飯,之後他的錢減少ai。
輸入項
第一行包含兩個整數n,q(1≤n,q≤2⋅105)。

第二行包含n個整數a1,a2,…,an(1≤ai≤109)-用餐費用。保證a1≥a2≥…≥an。

接下來的每行q包含三個整數t,x,y(1≤t≤2,1≤x≤n,1≤y≤109),每個整數描述下一個查詢。

確保至少存在一個型別2查詢。

輸出量
對於型別2的每個查詢,在新行上輸出答案。

//對於第二種操作,線上段樹上有技巧的遞迴,具體看程式碼 
 
//對於第一種操作
//二分出第一個小於等於y的位置p 
//如果大於x continue
//否則 up(p,x,y)
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
typedef long long ll;
int n,q;
int a[maxn];
struct node {
    
int l,r; ll sum; ll lazy; ll Min; }segTree[maxn<<2]; void build (int i,int l,int r) { segTree[i].l=l; segTree[i].r=r; if (l==r) { segTree[i].sum=a[l]; segTree[i].Min=a[l]; return; } int mid=(l+r)>>1; build(i<<1,l,mid); build(i
<<1|1,mid+1,r); segTree[i].sum=segTree[i<<1].sum+segTree[i<<1|1].sum; segTree[i].Min=min(segTree[i<<1].Min,segTree[i<<1|1].Min); } void spread (int i) { if (segTree[i].lazy) { segTree[i<<1].sum=segTree[i].lazy*(segTree[i<<1].r-segTree[i<<1].l+1); segTree[i<<1].Min=segTree[i].lazy; segTree[i<<1].lazy=segTree[i].lazy; segTree[i<<1|1].sum=segTree[i].lazy*(segTree[i<<1|1].r-segTree[i<<1|1].l+1); segTree[i<<1|1].Min=segTree[i].lazy; segTree[i<<1|1].lazy=segTree[i].lazy; segTree[i].lazy=0; } } void up (int i,int l,int r,ll v) { if (segTree[i].l>=l&&segTree[i].r<=r) { segTree[i].sum=v*(segTree[i].r-segTree[i].l+1); segTree[i].Min=v; segTree[i].lazy=v; return; } spread(i); int mid=(segTree[i].l+segTree[i].r)>>1; if (l<=mid) up(i<<1,l,r,v); if (r>mid) up(i<<1|1,l,r,v); segTree[i].sum=segTree[i<<1].sum+segTree[i<<1|1].sum; segTree[i].Min=min(segTree[i<<1].Min,segTree[i<<1|1].Min); } ll query (int i,int l,int r) { if (segTree[i].l>=l&&segTree[i].r<=r) { return segTree[i].sum; } spread(i); int mid=(segTree[i].l+segTree[i].r)>>1; ll ans=0; if (l<=mid) ans+=query(i<<1,l,r); if (r>mid) ans+=query(i<<1|1,l,r); return ans; } int q1 (int i,int l,int r,int &tt) { if (segTree[i].Min>tt) return 0; if (segTree[i].l>=l&&segTree[i].r<=r&&segTree[i].sum<=tt) { tt-=segTree[i].sum; return segTree[i].r-segTree[i].l+1; } spread(i); int mid=(segTree[i].l+segTree[i].r)>>1; int ans=0; if (l<=mid) ans+=q1(i<<1,l,r,tt); if (r>mid) ans+=q1(i<<1|1,l,r,tt); return ans; } int main () { scanf("%d%d",&n,&q); for (int i=1;i<=n;i++) scanf("%d",a+i); build(1,1,n); for (int i=1;i<=q;i++) { int t,x,y; scanf("%d%d%d",&t,&x,&y); if (t==1) { int l=1,r=n,p=n+1; while (l<=r) { int mid=(l+r)>>1; if (query(1,mid,mid)<=y) { p=mid; r=mid-1; } else { l=mid+1; } } if (p>x) continue; else up(1,p,x,y); } else { int ans=q1(1,x,n,y); printf("%d\n",ans); } } }