E. Greedy Shopping (thinking + line segment tree maintenance interval is the best value)

https://codeforces.com/contest/1440/problem/E

Question: There are n stores, it costs a[i] yuan to buy items in the i-th store. The sequence a is guaranteed to be non-increasing

Two operations:
① 1 xy set a[i] in the interval [1, x] to a[i] = max(a[i], y);
② 2 xy you have y yuan, starting from the number x Starting from the store, traverse all stores in turn until you reach store n, if you can buy the items in the current store, then buy. Ask how many items you can buy


Idea: In fact, the more obvious line segment tree requires a little thinking. Start dicing on the line segment tree. It is ok but it is more troublesome.

The first observation is a non-increasing sequence. So according to operation 1, if the maximum value of the currently covered interval <=y, then modify it, and if the minimum value of the currently covered interval>y, then it will not be modified. (Maintaining the minimum value is for pruning, otherwise TLE5) Then go to lazytag.

For operation two, interval query, if the minimum value of the current interval> x, it means that the interval does not need to be purchased. Otherwise, recurse the left subtree first, and then recurse the right subtree. If there is a range of intervals and <= own money, then buy it. Otherwise, you can't buy and continue recursively. Save money in the function reference when maintaining it.

The idea is not clear when writing, and the understanding of the line segment tree needs to be strengthened.

It is recommended that when the interval query is modified, the if judgment only judges whether the interval coverage is satisfied, and then various conditions are judged in it. Note that at this time, it is traversed to the leaf node and needs to calculate whether it can be bought, and pay attention to the recursive boundary.

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+100;
typedef long long LL;
LL a[maxn];
struct Tree{
    LL l,r,maxval,minval,sum,tag;///区间最大值,区间最小值,区间和,l
}tree[maxn*4];
void push_up(LL p)
{
    tree[p].maxval=max(tree[p*2].maxval,tree[p*2+1].maxval);
    tree[p].minval=min(tree[p*2].minval,tree[p*2+1].minval);
    tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
}
void addtag(LL p,LL d)
{
    tree[p].tag=d;
    tree[p].sum=tree[p].tag*(tree[p].r-tree[p].l+1);
    tree[p].maxval=tree[p].tag;
    tree[p].minval=tree[p].tag;
}
void push_down(LL p)
{
    if(tree[p].tag!=-1){
        addtag(p*2,tree[p].tag);
        addtag(p*2+1,tree[p].tag);
        tree[p].tag=-1;
    }
}
void build(LL p,LL l,LL r)
{
    tree[p].l=l;tree[p].r=r;tree[p].maxval=-1e18;tree[p].minval=1e18;
    tree[p].sum=0;tree[p].tag=-1;
    if(l==r) {tree[p].maxval=tree[p].minval=tree[p].sum=a[l];return;}
    LL mid=(l+r)>>1;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    push_up(p);
}
void modify(LL p,LL l,LL r,LL d)
{
    if(l<=tree[p].l&&r>=tree[p].r)///要修改的区间涵盖在区间内部
    {
        if(tree[p].minval>=d) return;///不剪枝会TLE5
        if(tree[p].maxval<d)
        {
            addtag(p,d);        return;
        }
        if(tree[p].l==tree[p].r) return;
    }
    push_down(p);
    LL mid=(tree[p].l+tree[p].r)>>1;
    if(l<=mid) modify(p*2,l,r,d);
    if(r>mid) modify(p*2+1,l,r,d);
    push_up(p);
}
LL query(LL p,LL l,LL r,LL &x)
{
    if(l<=tree[p].l&&r>=tree[p].r)
    {
        if(tree[p].minval>x) return 0;
        if(x>=tree[p].sum){
            x-=tree[p].sum;
            return tree[p].r-tree[p].l+1;
        }
        if(tree[p].l==tree[p].r) return 0;///返回到叶子节点的边界,注意叶子节点要考虑付钱
    }
    LL ans=0;
    push_down(p);
    LL mid=(tree[p].l+tree[p].r)>>1;
    if(l<=mid) ans+=query(p*2,l,r,x);
    if(r>mid) ans+=query(p*2+1,l,r,x);
    return ans;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n,m;cin>>n>>m;
  for(LL i=1;i<=n;i++) cin>>a[i];
  build(1,1,n);
  while(m--)
  {
      LL op,l,r;cin>>op>>l>>r;
      if(op==1){
        modify(1,1,l,r);
      }
      else if(op==2){
        cout<<query(1,l,n,r)<<endl;
      }
  }
return 0;
}

 

Guess you like

Origin blog.csdn.net/zstuyyyyccccbbbb/article/details/109824665