Cod sursa(job #1414199)

Utilizator gabrielinelusGabriel-Robert Inelus gabrielinelus Data 2 aprilie 2015 13:55:14
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.23 kb
/***********************
         z zzzz
                z
    *******      z
   **  66  *     88
   **  66   *88888888
   **  xxx   88888888
   *****TRACTORAS****
   * x *      * x *
    * *        * *
*********************/
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <bitset>

#define Nmax 100005
#define DIM 1666013
#define INF 0x3f3f3f3f

using namespace std;

bitset<Nmax> used;

vector<int> lantz[Nmax],G[Nmax];
int valori[Nmax]; /// valori[i] -> valoarea nodului i
int care_lantz[Nmax]; /// care_lantz[i] -> in ce lantz se afla nodul i
int poz_lantz[Nmax];  ///  poz_lantz[i] -> pe ce pozitie se afla in lant nodul i
int tata_lantz[Nmax]; /// tata_lantz[i] -> de ce nod se leaga lantul i
int greutate[Nmax]; /// greutate[i] -> greutatea subarborelui i
int adancime[Nmax]; /// adancime[i] -> adancimea nodului i

int _newX,A,B,pos,answer,N,M,LC;
int nrl = 1; /// nr lanturi

char buffer[DIM];
int poz = DIM - 1;

void Scanf(int &A){
    A = 0;
    while('0' > buffer[poz] || buffer[poz] > '9')
        if(++poz == DIM)
            fread(buffer,1,DIM,stdin),poz = 0;
    while('0' <= buffer[poz] && buffer[poz] <= '9')
    {
        A = A * 10 + buffer[poz] - 48;
        if(++poz == DIM)
            fread(buffer,1,DIM,stdin),poz = 0;
    }
}


class cmp{
public:
    bool operator()(const int &v1,const int &v2)const{
        return greutate[v1] > greutate[v2];
    }
};

class SegmentTree{
public:
    vector<int> range;
    void Resize(int lg){
        range.resize( 1 <<((int)ceil(log2((double)lg)) + 1));
    }
    void Build(int li,int lf,int pz)
    {
        if(li == lf){
            range[pz] = valori[lantz[LC][li]];
            return;
        }
        int m = li + ((lf - li) >> 1);
        Build(li,m,pz<<1);
        Build(m+1,lf,(pz<<1)|1);
        range[pz] = max(range[pz<<1],range[(pz<<1)|1]);
    }
    void Update(int li,int lf,int pz)
    {
        if(li == lf){
            range[pz] = _newX;
            valori[li] = _newX;
            return;
        }
        int m = li + ((lf - li) >> 1);
        if(pos <= m)
            Update(li,m,pz<<1);
        else
            Update(m+1,lf,(pz<<1)|1);
        range[pz] = max(range[pz<<1],range[(pz<<1)|1]);
    }
    void Querry(int li,int lf,int pz)
    {
        if(A <= li && lf <= B){
            answer = max(answer,range[pz]);
            return;
        }
        int m = li + ((lf - li) >> 1);
        if(A <= m)
            Querry(li,m,pz<<1);
        if(B > m)
            Querry(m+1,lf,(pz<<1)|1);
    }
};
SegmentTree Aint[Nmax];

void Read()
{
    Scanf(N);Scanf(M);
    for(int i = 1; i <= N; ++i)
        Scanf(valori[i]);
    int a,b;
    for(int i = 1; i < N; ++i)
    {
        Scanf(a);Scanf(b);
        G[a].push_back(b);
        G[b].push_back(a);
    }
}

void get_weight(int k)
{
    used[k] = 1;
    greutate[k] = 1;
    for(vector<int>::iterator it = G[k].begin(); it != G[k].end(); ++it)
        if(!used[*it]){
            adancime[*it] = adancime[k] + 1;
            get_weight(*it);
            greutate[k] += greutate[*it];
        }
}

void descomp(int k)
{
    used[k] = 1;
    lantz[nrl].push_back(k);
    care_lantz[k] = nrl;
    poz_lantz[k] = lantz[nrl].size() - 1;
    for(vector<int>::iterator it = G[k].begin(); it != G[k].end(); ++it)
        if(!used[*it])
        {
            if(lantz[nrl].back() != k){
                lantz[++nrl].push_back(0);
                tata_lantz[nrl] = k;
            }
            descomp(*it);
        }
}

void Decompose()
{
    adancime[1] = 1;
    get_weight(1);
    used = 0;
    for(int i = 1; i <= N; ++i)
        sort(G[i].begin(),G[i].end(),cmp());
    lantz[nrl].push_back(0);
    descomp(1);
}

void Build_trees()
{
    for(LC = 1; LC <= nrl; ++LC) /// fixam lantul curent
    {
        Aint[LC].Resize(lantz[LC].size() - 1);
        Aint[LC].Build(1,lantz[LC].size()-1,1);
    }
}

int Search(int x,int y)
{
    answer = -INF;
    while(care_lantz[x] != care_lantz[y])
    {
        if(adancime[tata_lantz[care_lantz[x]]] < adancime[tata_lantz[care_lantz[y]]])
            swap(x,y); /// deci nodul x trebuie sa fie cel care atunci cand se duce in sus ramane mai jos
        if(care_lantz[x] == 1)
            swap(x,y); /// nu mai am unde sa il urc pe nodul x, deci obligatoriu urc pe y
        LC = care_lantz[x];
        A = 1;
        B = poz_lantz[x];
        Aint[LC].Querry(1,lantz[LC].size()-1,1);
        x = tata_lantz[LC];
    }
    A = poz_lantz[x];
    B = poz_lantz[y];
    LC = care_lantz[x];
    if(A > B) swap(A,B);
    Aint[LC].Querry(1,lantz[LC].size()-1,1);
    return answer;
}

void Solve()
{
    int x,y,op;
    for(int i = 1; i <= M; ++i)
    {
        Scanf(op);Scanf(x);Scanf(y);
        if(op == 0)
        {/// facem update
            LC = care_lantz[x];
            _newX = y;
            pos = poz_lantz[x];
            Aint[LC].Update(1,lantz[LC].size()-1,1);
        }
        else
            printf("%d\n",Search(x,y));
    }
}

int main()
{
    freopen("heavypath.in","r",stdin);
    freopen("heavypath.out","w",stdout);

    Read();
    Decompose();
    Build_trees();
    Solve();

    return 0;
}