Cod sursa(job #891927)

Utilizator romircea2010FMI Trifan Mircea Mihai romircea2010 Data 25 februarie 2013 21:16:26
Problema Subsir crescator maximal Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 3.33 kb
// Subsir crescator maximal - complexitate O(NlogN), solutie cu arbori de intervale
#include <iostream>
#include <algorithm>
#include <fstream>
#include <vector>

using namespace std;

int n, a[100010], A, B, val, X, Y, position, sol, pozsol;
bool ok;
int best[100010], pred[100010];
vector <int> vsol;
struct arbore
{
    int minim, maxim, best, pos;
};
arbore aint[262150];

inline void Read()
{
    ifstream f("scmax.in");
    f>>n;
    int i;
    for(i=1; i<=n; i++)
        f>>a[i];
    f.close();
}

inline void Build(int nod, int st, int dr)
{
    if (st == dr)
    {
        aint[nod].minim = aint[nod].maxim = a[st];
        aint[nod].best = 1;
        aint[nod].pos = -1; // pos = pozitia in vectorul a in care se afla best
        return ;
    }
    int mij, fiu;
    mij = (st+dr)>>1;
    fiu = nod<<1;
    Build(fiu, st, mij);
    Build(fiu+1, mij+1, dr);

    aint[nod].minim = min(aint[fiu].minim, aint[fiu+1].minim);
    aint[nod].maxim = max(aint[fiu].maxim, aint[fiu+1].maxim);
    aint[nod].best = max(aint[fiu].best, aint[fiu+1].best);
    if (aint[fiu].best > aint[fiu+1].best)
        aint[nod].pos = aint[fiu].pos;
    else
        aint[nod].pos = aint[fiu+1].pos;
}

inline void Query(int nod, int st, int dr)
{
    if (A <= st && dr <= B && aint[nod].maxim < val)
    {
        if (aint[nod].best > X)
        {
            X = aint[nod].best;
            Y = aint[nod].pos;
			ok = true;
        }
        return ;
    }
    int mij, fiu;
    mij = (st+dr)>>1;
    fiu = nod<<1;
    if (A <= mij && aint[fiu].minim < val)
    {
        Query (fiu, st, mij);
    }
    if (mij < B && aint[fiu+1].minim < val)
    {
        Query (fiu+1, mij+1, dr);
    }
}

inline void Update(int nod, int st, int dr)
{
    if (st == dr)
    {
        aint[nod].best = val;
        aint[nod].pos = st; // = position
        return ;
    }
    int mij, fiu;
    mij = (st+dr)>>1;
    fiu = nod<<1;
    if (position <= mij)
    {
        Update(fiu, st, mij);
    }
    else
    {
        Update(fiu+1, mij+1, dr);
    }
    if (aint[fiu].best > aint[fiu+1].best)
    {
        aint[nod].best = aint[fiu].best;
        aint[nod].pos = aint[fiu].pos;
    }
    else
    {
        aint[nod].best = aint[fiu+1].best;
        aint[nod].pos = aint[fiu+1].pos;
    }
}

inline void Solve()
{
    Build(1, 1, n);
    int i;
    for(i=1; i<=n; i++)
    {
        val = a[i];
        A = 1;
        B = i-1;
        X = Y = 0;
		ok = false;
        Query(1, 1, n);
        // returneaza in X maximul dintre best[1 ... i-1] cu proprietatea ca a[j] < a[i]
        // si in Y pozitia in vectorul a la care se afla acest best;
		if (ok == false)
			Y = -1;
        best[i] = X + 1;
        pred[i] = Y;
        if (best[i] > sol)
        {
            sol = best[i];
            pozsol = i;
        }

        position = i;
        val = X + 1;
        Update(1, 1, n);
    }
}

inline void Write()
{
    ofstream g("scmax.out");
    g<<sol<<"\n";
    do
    {
        vsol.push_back(a[pozsol]);
        pozsol = pred[pozsol];
    } while (pozsol != -1);
    vector <int>::iterator it;
    for (it = vsol.end()-1; it >= vsol.begin(); it--)
        g<<*it<<" ";
    g<<"\n";
    g.close();
}

int main()
{
    Read();
    Solve();
    Write();
    return 0;
}