1. 程式人生 > 實用技巧 >Codeforces Round #684 (Div. 2)E. Greedy Shopping(線段樹區間最大值,最小值,區間和)

Codeforces Round #684 (Div. 2)E. Greedy Shopping(線段樹區間最大值,最小值,區間和)

題意:給出一個非嚴格遞減的子序列,需要完成 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;  //區間最大,最小,懶惰標記
ll 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)); } }
View Code