Solução OBI 2018 Baldes

February 3, 2020 | 4 min

Enunciado
Na minha primeira leitura, vi que esta é uma questão clássica de segtree. Um vetor de tamanho \(10^5\) e \(10^5\) queries dentro desse intervalo. Iremos fazer uma segtree para o mínimo num intervalo e outra para o máximo, sendo a resposta da query em um intervalo o max-min. Para simplificar isso, podemos guardar as duas árvores apenas em um vetor de pairs.

Porém após implementar a primeira solução e não funcionar fiz uma segunda leitura e percebi que o max e o min não podem estar no mesmo balde (na mesma posição no vetor). Então troquei o pair por uma struct, para guardar de qual balde o max e o min vieram. Quando o min e o max estiverem no mesmo balde temos uma certeza, um dos dois faz parte da solução. Nesse caso podemos testar, o query sem o min, mas com o max e o query sem o max, mas com o min.

#include <bits/stdc++.h>
typedef struct ii {
    int first;
    int second;
    int i;
    int j;
} ii;
using namespace std;

const int MAX = 5e5+50;
const int inf = 0x3f3f3f3f;

ii tree[MAX]={};
int arr[MAX];

ii merge(ii a, ii b) {

    ii c = {min(a.first,b.first),max(a.second,b.second),-1,-2};

    if(c.first==a.first) c.i=a.i;
    else c.i=b.i;

    if(c.second==a.second) c.j=a.j;
    else c.j=b.j;

    return c;
}

void build(int pos, int i, int j) {
    if(i==j) {
        tree[pos]={arr[i],arr[i],i,i};
        if(arr[i]==0) {
            tree[pos]={inf,-inf,-1,-2};
        }
    } else {
        build(2*pos,i,(i+j)/2);
        build(2*pos+1,(i+j)/2+1,j);

        tree[pos]=merge(tree[2*pos],tree[2*pos+1]);
    }
}

void update(int pos, int i, int j, int target, ii val) {
    if(i==j) {
        if(tree[pos].first!=0&&tree[pos].second!=0) {
            tree[pos]=merge(tree[pos],val);
        } else {
            tree[pos]=val; 
        }
    } else {
        if(target <= (i+j)/2) update(2*pos,i,(i+j)/2,target,val);
        else update(2*pos+1,(i+j)/2+1,j,target,val);

        tree[pos]=merge(tree[2*pos],tree[2*pos+1]);
    }
}

void force_update(int pos, int i, int j, int target, ii val) {
    if(i==j) {
        tree[pos]=val; 
    } else {
        if(target <= (i+j)/2) force_update(2*pos,i,(i+j)/2,target,val);
        else force_update(2*pos+1,(i+j)/2+1,j,target,val);
        tree[pos]=merge(tree[2*pos],tree[2*pos+1]);
    }
}

ii query(int pos, int i, int j, int a, int b) {
    if(i>b||j<a) {
        return {inf,-inf, -1, -2};
    } else if(i>=a&&j<=b) {
        return tree[pos];
    } else {
        return merge(query(2*pos,i,(i+j)/2,a,b),query(2*pos+1,(i+j)/2+1,j,a,b));
    }
}

int main() {

    int n,m;
    scanf("%d%d",&n,&m);

    for(int i=0;i<n;i++) scanf("%d",&arr[i]);

    build(1,0,n);

    for(int i=0;i<m;i++) {
        int op;
        scanf("%d",&op);

        if(op==1) {
            int w,p;
            scanf("%d%d",&w,&p);
            --p;
            update(1,0,n,p,{w,w,p,p});
        } else {
            int a,b;
            scanf("%d%d",&a,&b);
            --a,--b;
            ii p = query(1,0,n,a,b);

            if(p.i==p.j) {
                ii tmp = p;
                int ans=0;
                force_update(1,0,n,p.i,{p.first,-inf,p.i,p.j});
                ii A = query(1,0,n,a,b);
                force_update(1,0,n,p.i,{inf,p.second,p.i,p.j});
                ii B = query(1,0,n,a,b);

                ans=max(A.second-A.first,B.second-B.first);
                printf("%d\n",ans);

                update(1,0,n,p.i,p);
            } else {
                printf("%d\n",p.second-p.first);
            }
        }
        
    }

    return 0;
}