Cod sursa(job #891997)

Utilizator romircea2010FMI Trifan Mircea Mihai romircea2010 Data 25 februarie 2013 21:38:42
Problema Subsir crescator maximal Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 3.75 kb
// Subsir crescator maximal - complexitate O(NlogN), solutie cu arbori de intervale
#include <iostream>
#include <cstdio>
#include <cstring>
#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();

//    freopen ("scmax.in", "r", stdin);
//    scanf ("%d\n", &n);
//    char ch[3100000];
//    int lg;
//    gets(ch);
//    lg = strlen(ch);
//    int i, nr = 0, x;
//    for(i=0; i<lg; i++)
//    {
//        x = 0;
//        while (i<lg && ch[i] >= '0' && ch[i] <= '9')
//            x = x*10 + (int)(ch[i] - '0'), i++;
//        a[++nr] = x;
//    }
}

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()
{
    freopen ("scmax.out", "w", stdout);
    printf ("%d\n", sol);
    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--)
        printf ("%d ", *it);
    printf ("\n");
}

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