Cod sursa(job #843165)

Utilizator claudiumihailClaudiu Mihail claudiumihail Data 27 decembrie 2012 15:21:19
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 12.7 kb
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <iterator>
#include <vector>
#include <algorithm>
#include <limits>

#define MAX_SIZE 100001
 
using namespace std;
 
typedef unsigned int uint32;
 
template<class T, class Compare = less<T> >
class CIntervalTree
{
public:
 
    CIntervalTree(const int size, const T& defaultValue) :
        intervalSize(size)
    {
        vValues.resize(size + 1);
        vValues[size] = defaultValue;
        intervalTree = (int*)calloc((4*size+2), sizeof(int));
    }
    
    ~CIntervalTree()
    {
        vValues.clear();
        free(intervalTree);
    }
     
    inline void Update(const int index, const T& value)
    {
        vValues[index] = value;
        UpdateIndex(index);
    }
     
    inline void Update(const int index)
    {
        UpdateIndex(index);
    }
     
    inline void UpdateIndex(const int index)
    {
        int left = 0, right = intervalSize-1;
        int intervalTreeIndex = 0;
         
        while (left < right)
        {
            const int mid = left + (right-left)/2;
            if (index <= mid)
            {
                intervalTreeIndex = GetLeftSubtree(intervalTreeIndex);
                right = mid;
            }
            else
            {
                intervalTreeIndex = GetRightSubtree(intervalTreeIndex);
                left = mid+1;
            }
        }
         
        if (left == index)
        {
            intervalTree[intervalTreeIndex] = index;
             
            int parent = GetZeroBasedIndexOfParent(intervalTreeIndex);
 
            while(parent >= 0)
            {
                if (compare(vValues[intervalTree[GetLeftSubtree(parent)]], vValues[intervalTree[GetRightSubtree(parent)]]))
                {
                    intervalTree[parent] = intervalTree[GetLeftSubtree(parent)];
                }
                else
                {
                    intervalTree[parent] = intervalTree[GetRightSubtree(parent)];
                }
                 
                intervalTreeIndex = parent;
                parent = GetZeroBasedIndexOfParent(intervalTreeIndex);
            }
        }
    }
 
    inline int QueryIndex(const int l, const int r) const
    {
        int intervalTreeIndex = 0;
        int left = 0, right = intervalSize-1;
         
        if (l == r)
        {
            return QueryElementaryInterval(l);
        }
 
        int mid = left + (right-left)/2;
        while (r <= mid || l > mid)
        {
            if (r <= mid)
            {
                right = mid;
                intervalTreeIndex = GetLeftSubtree(intervalTreeIndex);
            }
            else if (l > mid)
            {
                left = mid+1;
                intervalTreeIndex = GetRightSubtree(intervalTreeIndex);
            }
             
            mid = left + (right-left)/2;
        }
         
        const int leftIndex = QueryLeftSubInterval(left, mid, l, GetLeftSubtree(intervalTreeIndex));
        const int rightIndex = QueryRightSubInterval(mid+1, right, r, GetRightSubtree(intervalTreeIndex));
         
        if (compare(vValues[leftIndex], vValues[rightIndex]))
        {
            return leftIndex;
        }
 
        return rightIndex;
    }
     
    inline T& QueryValue(const int l, const int r)
    {
        return vValues[QueryIndex(l,r)];
    }
     
    inline const T& QueryValue(const int l, const int r) const
    {
        return vValues[QueryIndex(l,r)];
    }
 
    inline T& GetValueAt(const int index)
    {
        return vValues[index];
    }
     
    inline const T& GetValueAt(const int index) const
    {
        return vValues[index];
    }
 
private:
    
    inline int GetZeroBasedIndexOfParent(int index) const
    {
        return (index-1-!(index%2)) / 2;
    }
    
    inline int GetLeftSubtree(int index) const
    {
        return (index<<1)+1;
    }
    
    inline int GetRightSubtree(int index) const
    {
        return (index+1)<<1;
    }
 
    inline int QueryElementaryInterval(const int index) const
    {
        int left = 0, right = intervalSize-1;
        int intervalTreeIndex = 0;
         
        while (left < right)
        {
            const int mid = left + (right-left)/2;
            if (index <= mid)
            {
                intervalTreeIndex = GetLeftSubtree(intervalTreeIndex);
                right = mid;
            }
            else
            {
                intervalTreeIndex = GetRightSubtree(intervalTreeIndex);
                left = mid+1;
            }
        }
         
        if (left == index)
        {
            return intervalTree[intervalTreeIndex];
        }
         
        return intervalTree[intervalSize];
    }
 
    inline int QueryLeftSubInterval(int left, int right, const int finalLeft, int intervalTreeIndex) const
    {
        int foundIndex = intervalSize;
         
        while (finalLeft != left)
        {
            const int mid = left + (right-left)/2;
             
            if (finalLeft <= mid)
            {
                if (compare(vValues[intervalTree[GetRightSubtree(intervalTreeIndex)]], vValues[foundIndex]))
                {
                    foundIndex = intervalTree[GetRightSubtree(intervalTreeIndex)];
                }
                 
                intervalTreeIndex = GetLeftSubtree(intervalTreeIndex);
                right = mid;
            }
            else
            {
                left = mid+1;
                intervalTreeIndex = GetRightSubtree(intervalTreeIndex);
            }
        }
         
        if (compare(vValues[intervalTree[intervalTreeIndex]], vValues[foundIndex]))
        {
            foundIndex = intervalTree[intervalTreeIndex];
        }
         
        return foundIndex;
    }
 
    inline int QueryRightSubInterval(int left, int right, const int finalRight, int intervalTreeIndex) const
    {   
        int foundIndex = intervalSize;
         
        while (finalRight != right)
        {
            const int mid = left + (right-left)/2;
 
            if (finalRight > mid)
            {
                if (compare(vValues[intervalTree[GetLeftSubtree(intervalTreeIndex)]], vValues[foundIndex]))
                {
                    foundIndex = intervalTree[GetLeftSubtree(intervalTreeIndex)];
                }
 
                intervalTreeIndex = GetRightSubtree(intervalTreeIndex);
                left = mid+1;
            }
            else
            {
                right = mid;
                intervalTreeIndex = GetLeftSubtree(intervalTreeIndex);
            }
        }
         
        if (compare(vValues[intervalTree[intervalTreeIndex]], vValues[foundIndex]))
        {
            foundIndex = intervalTree[intervalTreeIndex];
        }
         
        return foundIndex;
    }
 
    Compare         compare;
    const int       intervalSize;
    int             *intervalTree;
    vector<T>       vValues;
};

typedef vector<vector<int> > Graph;

struct VertexIndex
{
    int WhatPath;
    int WhatPosition;
};

struct Path
{
    Path() :
        Parent(-1),
        Level(std::numeric_limits<int>::max()),
        IntervalTree(NULL)
    {}
    
    ~Path()
    {
        if (IntervalTree != NULL)
        {
            delete IntervalTree;
        }
    }
    
    size_t size() const
    {
        return vVertexes.size();
    }

    int Parent;
    int Level;
    vector<int> vVertexes;
    CIntervalTree<int, greater<int> >* IntervalTree;
};

vector<VertexIndex> vVertexIndex;
vector<Path> vPaths;
Graph graph;

void DFS(int node, int depth)
{
    static bool vUsed[MAX_SIZE] = {true, false};
    static int vWeight[MAX_SIZE];
    
    int pathChosen = node;
    int maxWeight = -1;
    
    vUsed[node] = true;
    vWeight[node] = 1;
    
    for (vector<int>::const_iterator it=graph[node].begin();
         it != graph[node].end();
         ++it)
    {
        if (vUsed[*it] == false)
        {
            DFS(*it, depth+1);
            vWeight[node] += vWeight[*it];
            
            if (maxWeight < vWeight[*it])
            {
                maxWeight = vWeight[*it];
                pathChosen = vVertexIndex[*it].WhatPath;
            }
        }
    }

    vVertexIndex[node].WhatPath = pathChosen;
    vVertexIndex[node].WhatPosition = vPaths[pathChosen].size();
    vPaths[pathChosen].vVertexes.push_back(node);
    vPaths[pathChosen].Level = std::min(depth, vPaths[pathChosen].Level);
    
    for (vector<int>::const_iterator it=graph[node].begin();
         it != graph[node].end();
         ++it)
    {
        if (vVertexIndex[*it].WhatPath != pathChosen)
        {
            vPaths[vVertexIndex[*it].WhatPath].Parent = node;
        }
    }
}

int main()
{
    int n, m;
    vector<int> vVertexValues;
    fstream fin("heavypath.in", fstream::in);
    fstream fout("heavypath.out", fstream::out);
    
    fin >> n >> m;
    //cout << n << " " << m << endl;
    
    graph.resize(n);
    vVertexValues.resize(n);
    vVertexIndex.resize(n);
    vPaths.resize(n);
    
    for (int i=0; i<n; ++i)
    {
        fin >> vVertexValues[i];
        //cout << vVertexValues[i] << " ";
    }
    //cout << endl;
    
    for (int i=0; i<n-1; ++i)
    {
        int x, y;
        fin >> x >> y;
        
        graph[x-1].push_back(y-1);
        graph[y-1].push_back(x-1);
    }
    
    /*for (int i=0; i<n; ++i)
    {
        cout << i + 1 << " --> ";
        for (vector<int>::const_iterator it=graph[i].begin();
             it != graph[i].end();
             ++it)
        {
            cout << *it + 1 << " ";
        }
        cout << endl;
    }*/
    
    DFS(0, 0);
    
    for (int i=0; i<n; ++i)
    {
        graph[i].clear();
    }
    graph.clear();
    
    
    for (int i=0; i<vPaths.size(); ++i)
    {
        if (vPaths[i].Level < n)
        {
            reverse(vPaths[i].vVertexes.begin(), vPaths[i].vVertexes.end());

            vPaths[i].IntervalTree = new CIntervalTree<int, greater<int> >(vPaths[i].vVertexes.size(), 0);
            for (int j=0; j<vPaths[i].vVertexes.size(); ++j)
            {
                vPaths[i].IntervalTree->Update(j, vVertexValues[vPaths[i].vVertexes[j]]);
                vVertexIndex[vPaths[i].vVertexes[j]].WhatPosition = j;
            }
        }
    }

    vVertexValues.clear();

    /*for (int i=0; i<n; ++i)
    {
        cout << vVertexIndex[i].WhatPath << "  " << vVertexIndex[i].WhatPosition << endl;
    }
    cout << endl;*/
    
    /*for (int i=0; i<vPaths.size(); ++i)
    {
        if (vPaths[i].Level < n)
        {
            cout << vPaths[i].Parent << "  " << vPaths[i].Level << endl;
            for (int j=0; j<vPaths[i].vVertexes.size(); ++j)
            {
                cout << vPaths[i].vVertexes[j] << " ";
            }
            cout << endl << endl;
        }
    }*/
    
    for (int i=0; i<m; ++i)
    {
        int t, x, y;
        fin >> t >> x >> y;
        
        switch (t)
        {
            case 0:
            {
                vPaths[vVertexIndex[x-1].WhatPath].IntervalTree->Update(vVertexIndex[x-1].WhatPosition, y);
            }; break;
            
            case 1:
            {
                x--;
                y--;
                
                if (vPaths[vVertexIndex[x].WhatPath].Level < vPaths[vVertexIndex[y].WhatPath].Level)
                {
                    swap(x, y);
                }

                int ret = -1;
                int WhatPath = vVertexIndex[x].WhatPath;
                
                while (WhatPath != vVertexIndex[y].WhatPath)
                {
                    if (vPaths[vVertexIndex[x].WhatPath].Level < vPaths[vVertexIndex[y].WhatPath].Level)
                    {
                        swap(x, y);
                        WhatPath = vVertexIndex[x].WhatPath;
                    }

                    ret = std::max(ret, vPaths[WhatPath].IntervalTree->QueryValue(0, vVertexIndex[x].WhatPosition));
                    x = vPaths[WhatPath].Parent;
                    WhatPath = vVertexIndex[x].WhatPath;
                }
            
                if (vVertexIndex[x].WhatPosition > vVertexIndex[y].WhatPosition)
                {
                    swap(x, y);
                }
                
                ret = std::max(ret, vPaths[WhatPath].IntervalTree->QueryValue(vVertexIndex[x].WhatPosition, vVertexIndex[y].WhatPosition));
                
                fout << ret << "\n";
            }; break;
        }
    }

    fin.close();
    fout.close();
    return 0;
}