E. Compras codiciosas (pensar + intervalo de mantenimiento del árbol de segmento de línea es el mejor valor)

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

Pregunta: Hay n tiendas, cuesta un [i] yuan comprar artículos en la i-ésima tienda. Se garantiza que la secuencia a no aumentará

Dos operaciones:
① 1 xy establece a [i] en el intervalo [1, x] en a [i] = max (a [i], y);
② 2 xy tienes y yuan, comenzando desde el número x Comenzando desde la tienda, recorra todas las tiendas por turno hasta llegar a la tienda n, si puede comprar los artículos en la tienda actual, luego compre. Pregunte cuántos artículos puede comprar


Idea: De hecho, el árbol de segmento de línea más obvio requiere pensar un poco. Empiece a cortar en cubitos en el árbol del segmento de línea. Está bien, pero es más problemático.

La primera observación es una secuencia que no aumenta. Entonces, de acuerdo con la operación 1, si el valor máximo del intervalo cubierto actualmente <= y, entonces modifíquelo, y si el valor mínimo del intervalo cubierto actualmente> y, entonces no se modificará. (Mantener el valor mínimo es para podar, de lo contrario TLE5) Luego vaya a lazytag.

Para la operación dos, consulta de intervalo, si el valor mínimo del intervalo actual> x, significa que no es necesario comprar el intervalo. De lo contrario, recurra primero al subárbol izquierdo y luego recurra al subárbol derecho. Si hay un rango de intervalos y <= dinero propio, entonces cómprelo. De lo contrario, no puede comprar y continuar de forma recursiva. Ahorre dinero en la referencia de función al realizar el mantenimiento.

La idea no es clara al escribir y es necesario fortalecer la comprensión del árbol de segmentos de línea.

Se recomienda que cuando se modifique la consulta de intervalo, el juicio if solo juzgue si se satisface la cobertura del intervalo, y luego se juzguen varias condiciones en él. Tenga en cuenta que en este momento, se atraviesa hasta el nodo hoja y necesita calcular si se puede comprar y prestar atención al límite recursivo.

#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;
}

 

Supongo que te gusta

Origin blog.csdn.net/zstuyyyyccccbbbb/article/details/109824665
Recomendado
Clasificación