Codeforces Round #684 (Div. 2)E. Greedy Shopping(線段樹區間最大值,最小值,區間和)
阿新 • • 發佈:2020-11-21
題意:給出一個非嚴格遞減的子序列,需要完成 m 次操作,分為下列兩種型別:
1> 1 x y:將區間 [ 1 , x ] 中的數進行 a[ i ] = max( a[ i ] , y ) 操作
2> 2 x y:給出一個權值 y,從 x 開始往 n 走,遇到 a[ i ] 如果滿足 a[ i ] <= y,購買該商品,問可以多少商品
思路:對於1操作我們可以維護一個區間最大值,如果當前值大於區間最大值,我們就把改區間修改掉。
對於2操作,我麼維護一個區間最小值,和區間和,如果當前的 y 小於區間的最小值,返回 0。如果當前的 y 大於當前區間的和,表示可以購買該區間所有的
的商品,然後返回該區間的長度就可以了。
#include <iostream> #include <string.h> #include <string> #include<cstdio> #include <algorithm> #define ll long long using namespace std; const int N=2e5+10; int a[N]; int cnt; ll ans; struct node { ll l,r; // 左右區間的端點 ll Mi,Mx,lazy; //區間最大,最小,懶惰標記View Codell sum,len; //區間和,該節點對應的區間長度。 } tree[N<<2]; void pushup(int n) { tree[n].Mx=max(tree[n<<1].Mx,tree[n<<1|1].Mx); tree[n].Mi=min(tree[n<<1].Mi,tree[n<<1|1].Mi); tree[n].sum=tree[n<<1].sum+tree[n<<1|1].sum; } void pushdown(int n){ if(tree[n].lazy){int val=tree[n].lazy; tree[n<<1].Mi=tree[n<<1].Mx=tree[n<<1].lazy=val; tree[n<<1|1].Mi=tree[n<<1|1].Mx=tree[n<<1|1].lazy=val; tree[n<<1].sum=tree[n<<1].len*val; tree[n<<1|1].sum=tree[n<<1|1].len*val; tree[n].lazy=0; } } void build_tree(int n,int l,int r){ tree[n].l=l; tree[n].r=r; tree[n].lazy=0; tree[n].len=r-l+1; if(l==r) tree[n].Mi=tree[n].Mx=tree[n].sum=a[l]; else{ ll mid=(l+r)/2; int left_node= 2*n; int right_node=2*n+1; build_tree(left_node,l,mid); build_tree(right_node,mid+1,r); pushup(n); } } void update_tree(int n,int l,int r,int val ) { if(tree[n].Mi>=val) return ; if(tree[n].l>=l&&tree[n].r<=r&&tree[n].Mx<val){ tree[n].sum=(tree[n].len)*val; tree[n].Mi=tree[n].Mx=tree[n].lazy=val; return ; } /*如果當前區間的最大值比我要更改的值要小,那麼就把該區間修改掉。*/ pushdown(n); //向下更新。 ll mid=(tree[n].l+tree[n].r)/2; if(l<=mid) update_tree(n<<1,l,r,val); if(r>mid) update_tree(n<<1|1,l,r,val); pushup(n); } int query_tree(int n,int l,int r) { if(tree[n].Mi>cnt) //很重要的一個減枝,不然遞迴會爆記憶體。 return 0 ; if(tree[n].sum<=cnt&&tree[n].l>=l&&tree[n].r<=r){ cnt-=tree[n].sum; return tree[n].len; } /*如果當前剩餘的錢,可以購買該區間所有的商品,就把該區間所有的商品都買了*/ pushdown(n); ll mid=(tree[n].l+tree[n].r)/2; int tp=0; if(l<=mid) tp+=query_tree(n<<1,l,r); if(r>mid) tp+=query_tree(n<<1|1,l,r); return tp; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) cin>>a[i]; build_tree(1,1,n); while(m--){ int op,x,y; scanf("%d%d%d",&op,&x,&y); if(op==1) update_tree( 1, 1, x, y ); else cnt=y, printf("%d\n",query_tree( 1, x, n)); } }