Cod sursa(job #2266349)

Utilizator aaaapopa danut aaaa Data 22 octombrie 2018 16:34:39
Problema Arbori de intervale Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.65 kb
#include <iostream>
#include <vector>
#include <cassert>
#include <fstream>
using namespace std;

class arbint_iterativ{
    int n;
    vector<int> buf;
public:
    arbint_iterativ(vector<int>& vv): n(vv.size()), buf(2*n){
        for(int i = n; i < 2*n; ++i) buf[i] = vv[i];
        for(int i = n-1; i; --i) buf[i] = max(buf[2*i], buf[2*i+1]); }
    void update(int poz, int delta){
        for(buf[poz += n] = delta, poz/=2; poz; poz /= 2)
            buf[poz] = max(buf[2*poz], buf[2*poz+1]); }
    int query(int st, int dr){
        int rez = 0;
        for(st += n, dr += n+1; st < dr; st/=2, dr/=2){
            if(st%2) rez = max(rez, buf[st++]);
            if(dr%2) rez = max(rez, buf[--dr]); }
        return rez; } };


#define MAXN 131072
#define MINUS_INF 0
// == 2 ^ 17

int sir[MAXN] = {};

struct nod {
    nod *fiu_st, *fiu_dr;
    int st, dr, max; };

nod *build_arb(int st, int dr){
    // construieste un arbore care reprezinta subsecventa [st, dr]
    nod * rez = new nod;

    rez->st = st;
    rez->dr = dr;

    if(st == dr){
        rez->fiu_st = rez->fiu_dr = 0;
        rez->max = sir[st];
    }
    else{
        const int mij = (st+dr)/2;
        rez->fiu_st = build_arb(st, mij);
        rez->fiu_dr = build_arb(mij+1, dr);
        rez->max = max(rez->fiu_st->max, rez->fiu_dr->max);
    }
    return rez;
}

void schimba_valoare(nod *n, int poz, int val){
    assert(n->st <= poz && poz <= n->dr);
    if(n->st == n->dr){
        n->max = val;
        sir[poz] = val;
    }
    else{
        const int mij = (n->st+n->dr)/2;
        if(poz <= mij)
            schimba_valoare(n->fiu_st, poz, val); 
        else
            schimba_valoare(n->fiu_dr, poz, val);
        n->max = max(n->fiu_st->max, n->fiu_dr->max);
    }
}

int query_maxim(nod *n, int qst, int qdr){
    if(qst <= n->st && n->dr <= qdr) return n->max;
    if(n->dr < qst || qdr < n->st) return MINUS_INF;
    return max(query_maxim(n->fiu_st, qst, qdr),
        query_maxim(n->fiu_dr, qst, qdr));
}


void normalize(vector<int>& in){
    vector<int> sorted = in;
    sort(begin(sorted), end(sorted));
    for(int i = 0; i < in.size(); ++i){
        in[i] = lower_bound(begin(sorted), end(sorted), in[i]) - begin(sorted); } }

int main(){
    vector<int> v = {1, 100, 100, 1000 };
    normalize(v);
    for(auto& x : v) cout << x << ' ';


    ifstream f("arbint.in");
    ofstream g("arbint.out");
    int n, m;

    f >> n >> m;

    for(int i = 1; i <= n; ++i)
        f >> sir[i];

    nod *radacina = build_arb(1, MAXN);

    for(int i = 1, x, y, z; i <= m; ++i){
        f >> x >> y >> z;
        if(x == 0) g << query_maxim(radacina, y, z) << '\n';
        else schimba_valoare(radacina, y, z);
    }

    return 0;
}

/*
pentru subsir crescator maximal nlogn

d[i][j] = subsirul crescator maximal care incepe la o pozitite >= i,
    si ai carei prima valoarea este j

trecem de la i+1 la i avem o singura schimbare:
d[i][v[i]] = max(d[i+1][v[i]], 1 + d[i+1][>=v[i]])

OPTIMIZARE 1:
tinem doar un rand odata --> di[j] = d[i][j]

OPTIMIZARE 2:
observam ca trecerea de la di+1 la di include un query maxim pe subsecventa,
si o updatare de pozitie -- care se face cu arbint in log

=> se rezolva in nlogn


DATORII -- scadem dintr-o pozitie
           interogam un interval

pentru update de secventa si query de interval:
    update-ul nostru pana acum -> gaseste un drom
    query-ul nostru pana acum -> gaseste niste subsecvente

definim valoarea unui nod ca fiind suma valorilor de la radacina la el
    query-ul nostru devine -> update-ul vechi
    update-ul nostru nou devine -> query-ul vechi doar ca schimba starea

ceva de genul:

void update_secv(nod *n, int qst, int qdr, const int delta){
    if(qst <= n->st && n->dr <= qdr) n->sum += delta;
    if(n->dr < qst || qdr < n->st) ;
    update_secv(n->fiu_st, qst, qdr, delta);
    update_secv(n->fiu_dr, qst, qdr, delta);
}

sequence_query:

struct info{
    int best_atinge_st, best_atinge_dr, suma, best; };

info combine(info& st, info& dr){
    info rez;
    rez.best_atinge_st = max(st.best_atinge_st, st.suma + dr.best_atinge_st);
    rez.best_atinge_dr = max(dr.best_atinge_dr, dr.suma + st.best_atinge_dr);
    rez.suma = st.suma + dr.suma;
    rez.best = max(st.best_atinge_dr + dr.best_atinge_st, max(st.best, dr.best));
    return rez; }

info query_maxim(nod *n, int qst, int qdr){
    if(qst <= n->st && n->dr <= qdr) return n->informatie;
    info minus_inf = {};
    if(n->dr < qst || qdr < n->st) return minus_inf;
    return combine(query_maxim(n->fiu_st, qst, qdr),
        query_maxim(n->fiu_dr, qst, qdr));
}