Cod sursa(job #611694)

Utilizator proflaurianPanaete Adrian proflaurian Data 2 septembrie 2011 18:47:24
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.47 kb
#include<cstdio>
#include<cstring>
#include<vector>
#define N 1<<17
using namespace std;
struct AI{int BST,LO,HI;AI *TA,*FS,*FD;};
AI *ai[N],*Nod[N],*nd;
vector<int> v[N],P[N],p;
int n,q,i,x,y,t,z,V[N],niv[N],w[N],a[N],T[N],na,ST,DR,poz[N],DAD[N],Querry(int,int),QuerryA(AI*,int,int);
void df(int),arbore(AI*,AI*,int,int);
int main()
{
    freopen("heavypath.in","r",stdin);
    freopen("heavypath.out","w",stdout);
    scanf("%d%d",&n,&q);
    for(i=1;i<=n;i++)scanf("%d",&V[i]);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        v[x].push_back(y);v[y].push_back(x);
    }
    niv[1]=1;df(1);
    //am drumurile si constriuesc acum arborii de intervale
    for(i=1;i<=na;i++)
    {
        p.resize(0);
        ST=0;DR=-1;
        ai[i]=new AI;//initializez radacina arborelui;
        for(;P[i].size();){x=P[i].back();P[i].pop_back();p.push_back(x);DR++;poz[x]=DR;}
        arbore(0,ai[i],ST,DR);//construiesc arborele de intrvale corespunzator
    }
    for(;q;q--)
    {
        scanf("%d%d%d",&t,&x,&y);
        if(!t)
        {
            Nod[x]->BST=y;
            for(nd=Nod[x]->TA;nd;nd=nd->TA)nd->BST=max(nd->FS->BST,nd->FD->BST);
            continue;
        }
        printf("%d\n",Querry(x,y));

    }
    return 0;
}
void df(int nod)
{
    //setez greutatea nodului la 1;
    w[nod]=1;
    //daca nodul este frunza
    if(v[nod].size()==1&&nod!=1)
    {
        //construiesc un nou drum(care de fapt va fi un nou arbore de intervale)
        a[nod]=++na;
        P[na].push_back(nod);
        niv[nod]=niv[T[nod]]+1;
        DAD[a[nod]]=T[nod];
        return;
    }
    //daca nodul nu este frunza
    for(vector<int>::iterator it=v[nod].begin();it!=v[nod].end();it++)
    {
        //folosind tatal nodului calculez nivelul nodului
        if(*it==T[nod])
        {
            niv[nod]=niv[*it]+1;
            continue;
        }
        //pentru fii apelez df
        T[*it]=nod;
        df(*it);
        //folosesc greutatea fiilor pentru a calcula greutatea nodului
        w[nod]+=w[*it];
    }
    //incep a doua parcurgere sa determin fiul de greutate maxima
    int bst=0;
    for(vector<int>::iterator it=v[nod].begin();it!=v[nod].end();it++)
        //nu ma interezeaza tatal si fii de greutati mai mici decat cea mai buna de pana acum
        if(*it!=T[nod]&&w[*it]>bst)
        {
            //daca gasesc greutate mai mare updatez si redefinesc drumul la care lipesc nodul curent
            bst=w[*it];
            a[nod]=a[*it];
        }
    //pun nodul curent in arborele de intervale potrivit si actulaizez nodul la care se va lipi aceste
    P[a[nod]].push_back(nod);
    DAD[a[nod]]=T[nod];
}
void arbore(AI *DAD,AI *NOD,int st,int dr)
{
    AI *aux;
    NOD->LO=st;NOD->HI=dr;NOD->TA=DAD;
    if(st==dr){NOD->FS=NOD->FD=0;NOD->BST=V[p[st]];Nod[p[st]]=NOD;return;}
    aux=new AI;
    arbore(NOD,aux,st,(st+dr)/2);
    NOD->FS=aux;
    aux=new AI;
    arbore(NOD,aux,(st+dr)/2+1,dr);
    NOD->FD=aux;
    NOD->BST=max(NOD->FS->BST,NOD->FD->BST);
}
int Querry(int x1,int x2)
{
    if(a[x1]==a[x2]) return QuerryA(ai[a[x1]],min(poz[x1],poz[x2]),max(poz[x1],poz[x2]));
    if(niv[DAD[a[x1]]]<niv[DAD[a[x2]]]){z=x1;x1=x2;x2=z;}
    return max(QuerryA(ai[a[x1]],0,poz[x1]),Querry(DAD[a[x1]],x2));
}
int QuerryA(AI *NOD,int lo,int hi)
{
    if(lo>NOD->HI||hi<NOD->LO)return 0;
    if(lo<=NOD->LO&&NOD->HI<=hi)return NOD->BST;
    return max(QuerryA(NOD->FS,lo,hi),QuerryA(NOD->FD,lo,hi));
}