Cod sursa(job #1141191)

Utilizator mirceadinoMircea Popoveniuc mirceadino Data 12 martie 2014 18:20:24
Problema Heavy Path Decomposition Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 4.3 kb
#include<cstdio>
#include<vector>
#include<bitset>
#include<deque>
#include<algorithm>

using namespace std;

const int NMAX = 100000+5;
const int MMAX = 100000+5;
const int VMAX = 2000000000+5;

void Read(),Make_Paths(),Solve_Queries();
// Functii AInt
void Build(int,int,int,int);
void Update(int,int,int,int,int,int);
int Query(int,int,int,int,int,int);

int N,M,NrPaths;
int Val[NMAX]; // Val[i] = valoarea nodului i
int Dad[NMAX]; // Dad[i] = tatal nodului i
int Niv[NMAX]; // Niv[i] = nivelul nodului i
int Weight[NMAX]; // Weight[i] = greutatea subarborelui nodului i
int E[NMAX]; // E[i] = drumul pe care se afla nodul i
int Poz[NMAX]; // Poz[i] = pozitia in drumul sau pentru al i-lea nod
int PSize[NMAX]; // PSize[i] = dimensiunea celui de-al i-lea drum
vector<int> V[NMAX]; // arborele prin liste de adiacenta
vector<int> Path[NMAX]; // Path[i] = nodurile ce fac parte din al i-lea drum
bitset<NMAX> Viz;
int *AInt[NMAX];

void Read()
{
    int i,x,y;

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

    scanf("%d%d",&N,&M);

    for(i=1; i<=N; i++)
        scanf("%d",&Val[i]);

    for(i=1; i<=N-1; i++)
    {
        scanf("%d%d",&x,&y);
        V[x].push_back(y);
        V[y].push_back(x);
    }
}

inline bool cmp_w(int x,int y)
{
    return Weight[x]>Weight[y];
}

void DFS(int nod)
{
    vector<int>::iterator it;
    int aux=0;

    Viz[nod]=1;
    Weight[nod]=1;

    for(it=V[nod].begin(); it!=V[nod].end(); it++)
    {
        if(Viz[*it]) continue;
        Niv[*it]=Niv[nod]+1;
        DFS(*it);
        Dad[*it]=nod;
        Weight[nod]+=Weight[*it]; // Adunam greutatile fiilor la greutatea tatalui
        if(Weight[*it]>Weight[aux]) aux=*it; // Cautam cel mai greu fiu
    }

    if(Weight[nod]==1) // Daca nodul curent e o frunza...
    {
        NrPaths++; // ... incepem un drum nou
        Poz[nod]=0;
        Path[NrPaths].push_back(nod);
        E[nod]=NrPaths;
        PSize[NrPaths]++;
        return;
    }

    // Adaugam nodul curent la drumul sau
    Poz[nod]=Poz[Path[E[aux]].back()]+1;
    Path[E[aux]].push_back(nod);
    E[nod]=E[aux];
    PSize[E[aux]]++;
}

void Make_Paths()
{
    int i;

    Niv[1]=1;
    DFS(1);

    for(i=1; i<=NrPaths; i++)
    {
        // Drumul l-am facut de la frunza la radacina, asa ca il rotesc
        reverse(Path[i].begin(),Path[i].end());
        // Construiesc AInt pentru drumul curent
        AInt[i]=new int[3*PSize[i]];
        Build(1,1,PSize[i],i);
    }

    // Am rotit drumul, asa ca "rotesc" si pozitiile in drum
    for(i=1; i<=N; i++)
        Poz[i]=PSize[E[i]]-Poz[i];
}

int Solve(int x,int y)
{
    int ans=-1;
    while(1)
    {
        // Daca doua noduri sunt pe acelasi drum, scot solutia
        if(E[x]==E[y]) return max(ans,Query(1,1,PSize[E[x]],E[x],min(Poz[x],Poz[y]),max(Poz[x],Poz[y])));

        // Extrag solutia de pe o bucata de drum, apoi urc pe un drum superior
        if(Niv[Path[E[x]][0]] < Niv[Path[E[y]][0]]) swap(x,y);
        ans=max(ans,Query(1,1,PSize[E[x]],E[x],1,Poz[x]));
        x=Dad[Path[E[x]][0]];
    }
}

void Do_Queries()
{
    int t,x,y;

    for(; M; --M)
    {
        scanf("%d%d%d",&t,&x,&y);
        if(t==0) Update(1,1,PSize[E[x]],Poz[x],y,E[x]);
        else printf("%d\n",Solve(x,y));
    }
}

int main()
{
    Read();
    Make_Paths();
    Do_Queries();

    return 0;
}

void Build(int nod,int lo,int hi,int path)
{
    if(lo==hi)
    {
        AInt[path][nod]=Val[Path[path][lo-1]];
        return;
    }
    int mi=(lo+hi)/2;
    Build(2*nod,lo,mi,path);
    Build(2*nod+1,mi+1,hi,path);
    AInt[path][nod]=max(AInt[path][2*nod],AInt[path][2*nod+1]);
}

void Update(int nod,int lo,int hi,int poz,int val,int path)
{
    if(lo==hi)
    {
        AInt[path][nod]=val;
        return;
    }
    int mi=(lo+hi)/2;
    if(poz<=mi) Update(2*nod,lo,mi,poz,val,path);
    else Update(2*nod+1,mi+1,hi,poz,val,path);
    AInt[path][nod]=max(AInt[path][2*nod],AInt[path][2*nod+1]);
}

int Query(int nod,int lo,int hi,int path,int A,int B)
{
    if(A<=lo && hi<=B) return AInt[path][nod];
    if(B<lo || hi<A) return -1;
    int mi=(lo+hi)/2,st,dr;
    st=Query(2*nod,lo,mi,path,A,B);
    dr=Query(2*nod+1,mi+1,hi,path,A,B);
    return max(st,dr);
}