Cod sursa(job #1556221)

Utilizator bciobanuBogdan Ciobanu bciobanu Data 24 decembrie 2015 13:18:08
Problema Arbore Scor 10
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.41 kb
#include <fstream>
#include <bitset>
#include <cmath>
#include <random>
#include <iostream>
#include <cassert>

using namespace std;

const int MAX_N = 100000;
const int MAX_SQRT = 450;
const int MAX_V = 1e6;
const int NUM_SEARCH = 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 nodeEuler[2 * MAX_N];
int eulerPtr;

bitset <MAX_V + 1> D[MAX_SQRT];
int lazy[MAX_SQRT];

int sum[MAX_N];

int BUCKET_SIZE;

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;
    nodeEuler[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;
    nodeEuler[eulerPtr] = NIL;
    eulerPtr++;
}

inline int getRandom(void)
{
    static mt19937 gen(time(0));
    int x = gen();
    
    if (x < 0)
        x = -x;

    return x;
}

int randomSearch(int sum)
{
    for (int i = 0; i < NUM_SEARCH; i++)
    {
        int bucket = getRandom() % BUCKET_SIZE;

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

    }
    return BUCKET_SIZE;
}

int main()
{
    ifstream in("arbore.in");
    ofstream out("arbore.out");
    in.tie(0);
    ios_base::sync_with_stdio(0);
    int N, 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 = static_cast <int> (sqrt(eulerPtr - 1)) + 1;

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

    while (M--)
    {
        int opType;

        in >> opType;

        if (opType == 1)
        {
            int node, key, bucket, nextBucket;
            
            in >> node >> key;
            node--;

            bucket = E[node][0] / BUCKET_SIZE;
            nextBucket = (bucket + 1) * BUCKET_SIZE;

            for (int i = bucket * BUCKET_SIZE; i < nextBucket; i++)
                if (nodeEuler[i] != NIL)
                    D[bucket][ sum[ nodeEuler[i] ] ] = 0;

            for (int i = E[node][0]; i < nextBucket && i < E[node][1]; i++)
                if (nodeEuler[i] != NIL)
                    sum[ nodeEuler[i] ] += key;

            for (int i = bucket * BUCKET_SIZE; i < nextBucket; i++)
                if (nodeEuler[i] != NIL)
                    D[bucket][ sum[ nodeEuler[i] ] ] = 1;


            if (E[node][0] / BUCKET_SIZE != E[node][1] / BUCKET_SIZE)
            {
                int ptr = (bucket + 1)  * BUCKET_SIZE;
                while (ptr + BUCKET_SIZE <= E[node][1])
                {
                    lazy[ptr / BUCKET_SIZE] += key;
                    ptr += BUCKET_SIZE;
                }

                bucket = E[node][1] / BUCKET_SIZE;
                nextBucket = (bucket + 1) * BUCKET_SIZE;

                for (int i = bucket * BUCKET_SIZE; i < nextBucket; i++)
                    if (nodeEuler[i] != NIL)
                        D[bucket][ sum[ nodeEuler[i] ] ] = 0;

                for (int i = bucket * BUCKET_SIZE; i < E[node][1]; i++)
                    if (nodeEuler[i] != NIL)
                        sum[ nodeEuler[i] ] += key;

                for (int i = bucket * BUCKET_SIZE; i < nextBucket; i++)
                    if (nodeEuler[i] != NIL)
                        D[bucket][ sum[ nodeEuler[i] ] ] = 1;
            }
        }
        else
        {
            int bucket, key;

            in >> key;

            bucket = randomSearch(key);

            if (bucket == BUCKET_SIZE)
            {
                bucket = 0;

                while (bucket < BUCKET_SIZE && (key < lazy[bucket] || !D[bucket][key - lazy[bucket]]))
                    bucket++;
            }

            if (bucket != BUCKET_SIZE)
            {
                int eulerPos = bucket * BUCKET_SIZE;
                int nextBucket = (bucket + 1) * BUCKET_SIZE;
                key -= lazy[bucket];

                while (eulerPos < nextBucket && (nodeEuler[eulerPos] == NIL || sum[ nodeEuler[eulerPos] ] != key))
                    eulerPos++;

                assert(sum[nodeEuler[eulerPos]] == key);

                out << nodeEuler[eulerPos] + 1 << '\n';
            }
            else
                out << "-1\n";
        }
    }
    in.close();
    out.close();
    return 0;
}