Cod sursa(job #1556078)

Utilizator bciobanuBogdan Ciobanu bciobanu Data 24 decembrie 2015 01:46:13
Problema Arbore Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.04 kb
#include <fstream>
#include <cmath>
#include <bitset>
#include <random>

using namespace std;

const int MAX_N = 100000;
const int MAX_BUCKET = 450;
const int MAX_S = 1e6;
const int MAGIK = 64;
const int NIL = -1;

struct Edge 
{
    int v;
    int next;
};

Edge l[2 * MAX_N - 2];
int adj[MAX_N];
int E[MAX_N][2];
int nodeInEuler[2 * MAX_N];
int eulerPtr;

int sum[MAX_N + 1];

bitset <MAX_S + 2> D[MAX_BUCKET];
int lazy[MAX_BUCKET];

int BUCKET_SIZE;

int N;

void addEdge( int u, int v, int pos )
{
    l[pos].v = v;
    l[pos].next = adj[u];
    adj[u] = pos;
}

void DFS( int u, int par )
{
    E[u][0] = eulerPtr;
    nodeInEuler[eulerPtr] = u;
    eulerPtr++;

    for ( int i = adj[u]; i != NIL; i = l[i].next )
        if ( l[i].v != par )
            DFS( l[i].v, u );

    E[u][1] = eulerPtr;
    nodeInEuler[eulerPtr] = N;
    eulerPtr++;
}

inline int getRandom( void )
{
    static mt19937 gen( time(0) );
    int x = gen();
    return x < 0 ? -x : x;
}

inline int randomSearch( const int &sum )
{
    int bucket;

    for ( int i = 0; i < MAGIK; i++ )
    {
        bucket = getRandom() % BUCKET_SIZE;

        if ( sum >= lazy[bucket] && D[bucket][sum - lazy[bucket]] )
            return bucket;  
    }

    return BUCKET_SIZE;
}

int main(void)
{
    ifstream in("arbore.in");
    ofstream out("arbore.out");
    in.tie( 0 );
    ios_base::sync_with_stdio( 0 );
    int M;

    in >> N >> M;
    for ( int i = 0; i < N; i++ )
        adj[i] = NIL;
    for ( int i = 1; i < N; i++ )
    {
        int u, v;
        in >> u >> v;
        addEdge( u - 1, v - 1, 2 * i - 2 );
        addEdge( v - 1, u - 1, 2 * i - 1 );
    }

    DFS( 0, -1 );
    BUCKET_SIZE = sqrt( eulerPtr - 1 ) + 1;

    sum[N] = MAX_S + 1;
    for ( int i = 0; i < BUCKET_SIZE; i++ )
        D[i][0] = 1;

    while ( M-- )
    {
        int opType;
        in >> opType;

        if ( opType == 1 )
        {
            int node, s, ptr, where, nextBucket;
            in >> node >> s;
            node--;

            ptr = E[node][0];

            where = ptr / BUCKET_SIZE;
            nextBucket = ( where + 1 ) * BUCKET_SIZE;

            for ( int i = where * BUCKET_SIZE; i < nextBucket; i++ )
                D[where][ sum[ nodeInEuler[i] ] ] = 0;

            for ( int i = where * BUCKET_SIZE; i < nextBucket; i++ )
                sum[ nodeInEuler[i] ] += ( s & -( i <= E[node][1] ) );

            for ( int i = where * BUCKET_SIZE; i < nextBucket; i++ )
                D[where][ sum[ nodeInEuler[i] ] ] = 1;

            if ( E[node][0] / BUCKET_SIZE == E[node][1] / BUCKET_SIZE )
                continue;

            ptr = ( ptr / BUCKET_SIZE + 1 ) * BUCKET_SIZE;

            while ( ptr + BUCKET_SIZE <= E[node][1] )
            {
                lazy[ ptr / BUCKET_SIZE ] += s;
                ptr += BUCKET_SIZE;
            }

            if ( ptr <= E[node][1] )
            {
                where = ptr / BUCKET_SIZE;
                nextBucket = ( where + 1 ) * BUCKET_SIZE;

                for ( int i = where * BUCKET_SIZE; i < nextBucket; i++ )
                    D[where][ sum[ nodeInEuler[i] ] ] = 0;

                for ( int i = where * BUCKET_SIZE; i <= E[node][1]; i++ )
                    sum[ nodeInEuler[i] ] += s;

                for ( int i = where * BUCKET_SIZE; i < nextBucket; i++ )
                    D[where][ sum[ nodeInEuler[i] ] ] = 1;
            }
        }
        else
        {
            int s, tmp;

            in >> s;

            tmp = randomSearch( s );

            if ( tmp == BUCKET_SIZE )
            {
                tmp = 0;
                while ( (tmp < BUCKET_SIZE) && !D[tmp][s - lazy[tmp]] )
                    tmp++;
            }

            if ( tmp != BUCKET_SIZE )
            {
                int eulerPos = tmp * BUCKET_SIZE;
                while ( eulerPos < ( tmp + 1 ) * BUCKET_SIZE && sum[ nodeInEuler[eulerPos] ] + lazy[tmp] != s )
                    eulerPos++;
                out << 1 + nodeInEuler[eulerPos] << '\n';
            }
            else
                out << "-1\n";
        }
    }
    in.close();
    out.close();
    return 0;
}