• 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
    ",query_tree( 1, x, n));
        }
    }
    View Code
  • 相关阅读:
    进度条2
    VW
    SET和MAP
    解构赋值、
    Symbol
    箭头函数
    正则的补充
    java 面向对象(三十五):泛型在继承上的体现
    java 面向对象(三十六):泛型五 通配符
    java IO流 (一) File类的使用
  • 原文地址:https://www.cnblogs.com/sszywq/p/14016371.html
Copyright © 2020-2023  润新知