Cod sursa(job #849219)

Utilizator vendettaSalajan Razvan vendetta Data 6 ianuarie 2013 18:50:25
Problema Distincte Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.53 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <set>
#include <queue>
#include <deque>

using namespace std;

ifstream f("distincte.in");
ofstream g("distincte.out");

#define nmax 100005
#define ll long long
#define MOD 666013

int n, K, M, a[nmax], urm[nmax], viz[nmax];
vector< int > aint[nmax];
vector<int> sum[nmax];

void citeste(){
    f >> n >> K >> M;
    for(int i=1; i<=n; ++i) f >> a[i];
}

inline bool cmp(int A, int B){
    return urm[A] < urm[B];
}

void faAint(int nod, int st, int dr){
    if (st == dr){
        aint[nod].push_back( st );
        sum[nod].push_back( a[st] );
        return;
    }
    int mij = (st + dr) / 2;
    faAint(nod*2, st, mij);
    faAint(nod*2+1, mij+1, dr);
    // interclasez fii

    aint[nod].clear();
    for(int i=0; i<aint[nod*2].size(); ++i) aint[nod].push_back( aint[nod*2][i] );
    for(int i=0; i<aint[nod*2+1].size(); ++i) aint[nod].push_back( aint[nod*2+1][i] );
    sort(aint[nod].begin(), aint[nod].end(), cmp);
    //acum fac sumele partiale
    sum[nod].clear();
    sum[nod].push_back( a[ aint[nod][0] ] );
    for(int j=1; j<aint[nod].size(); ++j){
        sum[nod].push_back( (sum[nod][j-1] + a[ aint[nod][j] ]) );
    }
}

int cb(int st, int dr, int nod, int val){
    while(dr-st > 1){
        int mij = (st + dr) / 2;
        if ( urm[ aint[nod][mij] ] >= val){
            dr = mij;
        }else st = mij;
    }
    //if (dr == aint[nod].size()) return dr-1;
    return dr;
}

void query(int nod, int st, int dr, int A, int b, int &cnt){
    //cout << nod << "\n";
    if (A <= st && dr <= b){
        //acum vad care dintre y intra; practic am nevoie doar de capatul stang ca eu stiu ca se termina in n+1;
        if (aint[nod].size() == 1){
            int X = aint[nod][0];
            if ( urm[ aint[nod][0] ] > b) cnt += a[X];
            return;
        }
        int newy = cb(-1, aint[nod].size(), nod, b+1);
        int ceva = 0; if (newy > 0) ceva = sum[nod][newy-1];
        ceva = (sum[nod][ aint[nod].size()-1 ] - ceva );
        cnt += ceva;
        return;
    }else {
        int mij = (st + dr) / 2;
        if (A <= mij) query(nod*2, st, mij, A, b, cnt);
        if (b > mij) query(nod*2+1, mij+1, dr, A, b, cnt);
    }
}

void debug(){
    for(int i=1; i<=n; ++i) cout << urm[i] << " ";
    cout << "\n";
}

void rezolva(){
    // problema se poate simplifica daca fiecarui punct ii aflu urmatoare pozitie pe care apare; avand calculat acest lucru
    // o sa am ceva de forma (i, urm[i]); le pun intr-un sistem de coordonate si astfel acum pentru un query (x, y) ma intereseaza
    // elementele ce se afla cu coordoanata x(adica i-ul ) intre x si y iar urmatoarea lor aparitie e intre y+1 si n+1;
    // adica ultima data cand apar elemenetele sunt in afara intervalului x, y;
    // acum ma folosesc de un aint2d in care fiecare nod are intervalul sau st, dr si tine minte suma tututor elementelor cu x-ul intre st, dr
    // fac ceva sume partiale in fiecare nod in aint si atunci pentru un query caut y-ci si aflu suma;
    for(int i=1; i<=K; ++i) viz[i] = n+1;
    for(int i=n; i>=1; --i){
        urm[i] = viz[a[i]]; viz[a[i]] = i;
    }
    //debug();

    //faAint(1, 1, n);

    for(int i=1; i<=M; ++i){
        int x, y;f >> x >> y;
        //cout << x << " " << y << "\n";
        int s = 0;
        //query(1, 1, n, x, y, s);
        //cout << s << "\n";
        g << s%MOD << "\n";
    }
}

int main(){
    citeste();
    rezolva();

    f.close();
    g.close();

    return 0;
}