Cod sursa(job #2843911)

Utilizator Stefan_DomuncoStefan Domunco Stefan_Domunco Data 3 februarie 2022 11:30:01
Problema Heavy Path Decomposition Scor 80
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.05 kb
#include <bits/stdc++.h>

using namespace std;

ifstream fin("heavypath.in");
ofstream fout("heavypath.out");

const int NMAX = 1e5 + 5;
int n, q, depth[NMAX], where[NMAX];//where[i] - lantul unde se afla nodul i
vector <int> g[NMAX];
int values[NMAX];//valorile nodurilor
int weight[NMAX]; // greutatea fiecarui nod
int nrChains;
int pozChain[NMAX]; // pozitia nodului in lantul din care face parte

struct pathdecomp
{
    int father;
    vector <int> path;//retin lantul
}chains[NMAX];

inline void citire()
{
    fin >> n >> q;
    int i;
    for(i = 1; i <= n; ++i)
        fin >> values[i];

    for(i = 1; i < n; ++i)
    {
        int a, b;
        fin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
}

pair <int, int> maxSon[NMAX]; // weight-ul maxim al unui fiu al nodului i si nodul asociat maximului

//determin weight-ul
int calcWeight(int node, int d)
{
    depth[node] = d;
    weight[node] = 1;

    for(auto &it: g[node])
    {
        if(weight[it] == 0)// daca nu e vizitat
        {
            weight[node] += calcWeight(it, d + 1);
            if(maxSon[node].first < weight[it])
                maxSon[node].first = weight[it], maxSon[node].second = it;
        }
    }

    return weight[node];
}

bitset <NMAX> viz(0);

void createChains(int node, int chainNumber)
{
    where[node] = chainNumber;

    //indexare de la 1
    if(chains[chainNumber].path.empty())
        chains[chainNumber].path.push_back(0);

    chains[chainNumber].path.push_back(node);
    pozChain[node] = chains[chainNumber].path.size() - 1;
    for(auto &it: g[node])
    {
        if(depth[it] < depth[node])
            continue;

        if(it == maxSon[node].second) // daca am gasit maximul
            createChains(it, chainNumber);
        else
        {
            ++nrChains;
            chains[nrChains].father = node;
            createChains(it, nrChains);
        }
    }
}

vector < vector <int> > AINT; // AINT[i] - arborele de intervale asociat lantului i

void intAINT(int chainNumber, int node, int st, int dr)
{
    if(st == dr)
        AINT[chainNumber][node] = values[chains[chainNumber].path[st]];
    else
    {
        int mij = (st + dr) / 2;
        intAINT(chainNumber, 2 * node, st, mij);
        intAINT(chainNumber, 2 * node + 1, mij + 1, dr);
        AINT[chainNumber][node] = max(AINT[chainNumber][2 * node], AINT[chainNumber][2 * node + 1]);
    }
}

inline void init_AINT()
{
    int i;
    AINT.resize(nrChains + 2);
    for(i = 1; i <= nrChains; ++i)
    {
        AINT[i].resize(1ll << int(log2(chains[i].path.size()) + 2));
        intAINT(i, 1, 1, chains[i].path.size() - 1);
    }

}

inline void update_AINT(int chainNumber, int node, int st, int dr, int poz, int val)
{
    if(st == dr && st == poz)
        AINT[chainNumber][node] = val;
    else
    {
        int mij = (st + dr) / 2;
        if(poz <= mij)
            update_AINT(chainNumber, 2 * node, st, mij, poz, val);
        else update_AINT(chainNumber, 2 * node + 1, mij + 1, dr, poz, val);

        AINT[chainNumber][node] = max(AINT[chainNumber][2 * node], AINT[chainNumber][2 * node + 1]);
    }
}

int query_AINT(int chainNumber, int node, int st, int dr, int start, int stop)
{
    if(start <= st && dr <= stop)
        return AINT[chainNumber][node];
    else
    {
        int mij = (st + dr) / 2, a1, a2;
        a1 = a2 = INT_MIN;

        if(start <=  mij) // am o parte din interval in stangas
            a1 = query_AINT(chainNumber, 2 * node, st, mij, start, stop);

        if(stop > mij) // am o parte din interval in dreapta
            a2 = query_AINT(chainNumber, 2 * node + 1, mij + 1, dr, start, stop);

        return max(a1, a2);
    }
}

int answerQuery(int x, int y)//y stramos al lui x
{
    //sunt in acelasi lant
    if(where[x] == where[y])
    {
        int aux = query_AINT(where[x], 1, 1, chains[where[x]].path.size() - 1, min(pozChain[x], pozChain[y]), max(pozChain[x], pozChain[y]));
        return aux;
    }

    //daca nu este indeplinita conditia de stramos
    if(depth[chains[where[x]].father] < depth[chains[where[y]].father])
        swap(x, y);

    int a1 = query_AINT(where[x], 1, 1, chains[where[x]].path.size() - 1, 1, pozChain[x]);
    int a2 = answerQuery(chains[where[x]].father, y);

    return max(a1, a2);
}

int main()
{
    memset(depth, 0, sizeof depth);
    memset(where, 0, sizeof where);
    memset(weight, 0, sizeof weight);
    memset(values, 0, sizeof values);

    citire();
    calcWeight(1, 1);

    ++nrChains;
    chains[1].father = 0;
    createChains(1, 1);

    init_AINT();

    int i;

    int query_type, x, y;
    for(int i = 1; i <= q; ++i)
    {
        fin >> query_type >> x >> y;

        if(query_type == 0)//update in AINT, indicele x devine y
        {
            update_AINT(where[x], 1, 1, chains[where[x]].path.size() - 1, pozChain[x], y);
        }
        else
        {
            fout << answerQuery(x, y) << '\n';
        }
    }


    return 0;
}