Cod sursa(job #2198544)

Utilizator ZanoxNonea Victor Zanox Data 24 aprilie 2018 17:12:13
Problema Heavy Path Decomposition Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 6.67 kb
#include <fstream>
#include <vector>
#include <algorithm>
#include <iostream>

#define nrange 100000

int vals[nrange+1],nodeToChain[nrange+1],nodeToChainPos[nrange+1],
    parentNode[nrange+1],nodeHeight[nrange+1],noAncestors[nrange+1];

std::vector<int> edge[nrange+1],topOfChain;


std::vector<std::vector<int>> chains;

struct intv_node
{
    int val,l1,l2;
    intv_node *c1,*c2,*p;
};

std::vector<intv_node*> intvTrees;

void UpdateIntvTree(intv_node*,std::vector<int>&);
void BuildChains(int);
void MarkParents(int);
void CountHeight(int,int);
void CountAncestors(int);
intv_node* BuildIntvTree(int,int);
intv_node* SearchIntvTree(intv_node*,int);
void update(int,int);
int querry(int,int);
int QuerryIntvTree(intv_node*,int,int,std::vector<int>&);

#define chainToIntvTree(a) intvTrees[a]
#define chainHeight(a) nodeHeight[topOfChain[a]]

#define check std::cout<<"check\n";
#define print(a) std::cout<<"print "<<a<<'\n';
#define print_chains \
{\
    for(int i=0;i<chains.size();i++)\
    {\
        for(int j=0;j<chains[i].size();j++)\
            std::cout<<chains[i][j]<<' ';\
        std::cout<<'\n';\
    }\
}

int main()
{
    std::fstream fin("heavypath.in",std::ios::in),fout("heavypath.out",std::ios::out);
    int n,m;
    fin>>n>>m;
    for(int i=1;i<=n;i++)fin>>vals[i];
    for(int i=1;i<n;i++)
    {
        int a,b;
        fin>>a>>b;
        edge[a].push_back(b);
        edge[b].push_back(a);
    }

    MarkParents(1);
    CountHeight(1,0);
    CountAncestors(1);

    BuildChains(1);
//print(vals[7]);
    for(int i=0;i<chains.size();i++)
        intvTrees.push_back(BuildIntvTree(0,chains[i].size()));

    for(int i=1;i<=n;i++)
    {
        int chainId=nodeToChain[i];
        std::vector<int>&chain=chains[chainId];
        int pos=nodeToChainPos[i];
        intv_node *intvTreeRoot=chainToIntvTree(chainId);
        intv_node *exactLeaf=SearchIntvTree(intvTreeRoot,pos);

        UpdateIntvTree(exactLeaf,chain);
    }
//print_chains
    for(int i=1;i<=m;i++)
    {
        int t;
        fin>>t;
        if(t==0)
        {
            int x,val;
            fin>>x>>val;
            update(x,val);
        }
        else
        {
            int a,b;
            fin>>a>>b;
            fout<<querry(a,b)<<'\n';
        }
    }
}

void MarkParents(int node)
{
    for(std::vector<int>::iterator it=edge[node].begin();
        it!=edge[node].end();it++)
        if(*it!=parentNode[node])
        {
            parentNode[*it]=node;
            MarkParents(*it);
        }
}

void CountHeight(int node,int h)
{
    nodeHeight[node]=h;

    for(std::vector<int>::iterator it=edge[node].begin();
        it!=edge[node].end();it++)
        if(*it!=parentNode[node])

            CountHeight(*it,h+1);
}

void CountAncestors(int node)
{
    int&noa=noAncestors[node];
    noa=0;

    for(std::vector<int>::iterator it=edge[node].begin();
        it!=edge[node].end();it++)
        if(*it!=parentNode[node])
        {
            CountAncestors(*it);
            noa+=1+noAncestors[*it];
        }
}

intv_node* SearchIntvTree(intv_node* node,int pos)
{
    if(node->l1==node->l2)return node;

    int l=(node->l1+node->l2)/2;
    if(pos<=l)return SearchIntvTree(node->c1,pos);
    return SearchIntvTree(node->c2,pos);
}

int QuerryIntvTree(intv_node* node,int l1,int l2,std::vector<int>&v)
{//print(node->l1) print(node->l2) print(l1) print(l2) check
    if(l1==node->l1&&l2==node->l2)return node->val;

    int l=(node->l1+node->l2)/2;
    if(l1>l)return QuerryIntvTree(node->c2,l1,l2,v);
    if(l2<=l)return QuerryIntvTree(node->c1,l1,l2,v);

    int v1=QuerryIntvTree(node->c1,l1,l,v);
    int v2=QuerryIntvTree(node->c2,l+1,l2,v);
    if(v[v1]>v[v2])return v1;
    return v2;
}

void UpdateIntvTree(intv_node *node,std::vector<int>&v)
{
    if(node->l1==node->l2)
        node->val=node->l1;
    else
    {
        if(vals[v[node->c1->val]]>vals[v[node->c2->val]])
            node->val=node->c1->val;
        else node->val=node->c2->val;
    }

    if(node->p!=NULL)UpdateIntvTree(node->p,v);
}

intv_node* BuildIntvTree(int l1,int l2)
{
    intv_node* intvNode=new intv_node;
    intvNode->l1=l1;
    intvNode->l2=l2;
    intvNode->p=NULL;
    intvNode->val=0;

    if(l1==l2)
    {
        return intvNode;
    }

    int l=(l1+l2)/2;
    intvNode->c1=BuildIntvTree(l1,l);
    intvNode->c2=BuildIntvTree(l+1,l2);

    intvNode->c1->p=intvNode;
    intvNode->c2->p=intvNode;

    return intvNode;
}

void BuildChains(int node)
{
    int bestChild=0,valOfBest=0;

    if((edge[node].size()==1&&node!=1)||edge[node].size()==0)
    {
        int chainId=chains.size();
        std::vector<int>chain;
        chain.push_back(node);
        chains.push_back(chain);

        nodeToChain[node]=chainId;
        nodeToChainPos[node]=0;
        topOfChain.push_back(node);
        return;

    }

    for(std::vector<int>::iterator it=edge[node].begin();
        it!=edge[node].end();it++)
        if(*it!=parentNode[node])
    {
        if(noAncestors[*it]>valOfBest||bestChild==0)
        {
            valOfBest=noAncestors[*it];
            bestChild=*it;
        }
        BuildChains(*it);
    }


    int chainId=nodeToChain[bestChild];
    std::vector<int>&chain=chains[chainId];

    nodeToChain[node]=chainId;
    nodeToChainPos[node]=chain.size();
    topOfChain[chainId]=node;
    chain.push_back(node);

}

void update(int x,int val)
{
    vals[x]=val;

    int chainId=nodeToChain[x];
    int posInChain=nodeToChainPos[x];
    intv_node *intvTreeRoot=chainToIntvTree(chainId);

    intv_node *exactLeaf=SearchIntvTree(intvTreeRoot,posInChain);
    std::vector<int>&chain=chains[chainId];
    UpdateIntvTree(exactLeaf,chain);
}
//int count;
int querry(int x1,int x2)
{//print(x1) print(x2) check
    int chain1=nodeToChain[x1];
    int chain2=nodeToChain[x2];

    if(chain1==chain2)
    {
        int&chain=chain1;

        int pos1=nodeToChainPos[x1];
        int pos2=nodeToChainPos[x2];
        if(pos2<pos1)std::swap<int>(pos1,pos2);

        intv_node *intvTree=chainToIntvTree(chain);

        return vals[chains[chain][QuerryIntvTree(intvTree,pos1,pos2,chains[chain])]];
    }


    if(chainHeight(chain2)>chainHeight(chain1))
    {
        std::swap<int>(x1,x2);
        std::swap<int>(chain1,chain2);
    }

    int v1=QuerryIntvTree(chainToIntvTree(chain1),nodeToChainPos[x1],nodeToChainPos[topOfChain[chain1]],chains[chain1]);
//if(x1==7)std::cout<<vals[7]<<'\n';
    int newX1=parentNode[topOfChain[chain1]];
    int val2=querry(newX1,x2);

    return std::max(vals[chains[chain1][v1]],val2);
}