Cod sursa(job #1491215)

Utilizator daniel.grosuDaniel Grosu daniel.grosu Data 24 septembrie 2015 22:33:54
Problema Heavy Path Decomposition Scor 40
Compilator cpp Status done
Runda Arhiva educationala Marime 5.92 kb
#define REP(a,b) for(int a=0; a<(b); ++a)
#define REP2(a,b) for(int a=1; a<=(b); ++a)
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b)-1; a>=(c); --a)
#define BCK2(a,b,c) for(int a=(b); a>(c); --a)
#define FWDS(a,b,c,d) for(int a=(b); a<(c); a+=d)
#define ALL(a) (a).begin(), (a).end()
#define SIZE(a) ((int)(a).size())
#define VAR(x) #x ": " << x << " "
#define FILL(x,y) memset(x,y,sizeof(x))
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#define FAST ios_base::sync_with_stdio(0);cin.tie(0);
#define x first
#define y second
#define st first
#define nd second
#define mp make_pair
#define pb push_back
#define l(n) (n<<1)
#define r(n) ((n<<1)+1)
#define f(n) (n>>1)
#define lsb(a) (a&-a)

#include<vector>
#include<stack>
#include<queue>
#include<algorithm>

using namespace std;
#ifndef ONLINE_JUDGE
#include<fstream>
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
#else
#include<iostream>
#endif

const int NMAX = 100005;
const int dx[] = {0, 0, -1, 1}; //1,1,-1,1};
const int dy[] = {-1, 1, 0, 0}; //1,-1,1,-1};

typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;

int N,M,A[NMAX]; 

VI G[NMAX], P[NMAX]; // Graph and paths
int path[NMAX]; // Index of the path on which node n stands;
int conn[NMAX]; // The connection node of the path to the above path
int conn_lvl[NMAX]; // The connection node lvl; a.k.a. the starting high level;
int length[NMAX]; // The length of the path
int position[NMAX]; // The starting position of the path in the ST.
int K;

int segment[4*NMAX];

bool viz[NMAX]; // use for DFS
int w[NMAX]; // weight
int lvl[NMAX]; // depth of the node starting from the root
int asd;
void dfs(int n)
{
    //cout<<"n = "<<n<<" ";
    
    viz[n]=true;
    w[n]=1;
    
    int son=0;
    bool end=true;
    REP(i,G[n].size())
    {
        int curr=G[n][i];
        if(!viz[curr])
        {
            end=false;
            lvl[curr]=lvl[n]+1;
            dfs(curr);
            
            w[n]+=w[curr];
            if(!son)
                son=curr;
            else
                if(w[son] < w[curr])
                    son=curr;
        }
    }
    if(end) // it's a leaf so we create a new path
    {
        //cout<<"new path \n";
        path[n]=++K;
        length[path[n]]=1;
        P[path[n]].pb(n);
        return;
    }
    else // it's not a leaf so adhere this node to the path of the chosen son
    {
        path[n]=path[son];
        length[path[n]]++;
        P[path[son]].pb(n);

        // connect the paths ending in this node to this node
        REP(i, G[n].size())
        {
            int curr=G[n][i];
            if(curr == son || lvl[curr] < lvl[n])
                continue;
                
            if(!conn[path[curr]])
            {
                conn[path[curr]]=n;
                //cout<<"conn["<<path[curr]<<"] = "<<n<<" \n";
                conn_lvl[path[curr]]=lvl[n];
            }
        }
    }
}

void build(int n, int l, int r, int phi, int path)
{
    if(n+phi>4*NMAX){
        //cout<<"over flow \n "; return;
    }
    //cout<<n<<" "<<l<<" "<<r<<" \n";
    if(l==r)
    {
        segment[n + phi] = A[P[path][l-1]];
        return;
    }
    
    int pivot = (l + r)/2;
    
    build(l(n), l, pivot, phi, path);
    build(r(n), pivot+1, r, phi, path);
    
    segment[n + phi] = MAX(segment[l(n) + phi], segment[r(n) + phi]);
}

void update(int n, int l, int r, int poz, int val, int phi)
{
    if(l==r)
    {
        segment[n + phi]=val;
        //cout<<"updated ! "<<"\n";
        return;
    }
    
    int pivot = (l+r)>>1;
    
    if(poz <= pivot)
        update(l(n), l, pivot, poz, val, phi);
    else
        update(r(n), pivot+1, r, poz, val, phi);
    
    segment[n + phi] = MAX(segment[l(n) + phi], segment[r(n) + phi]);
    //cout<<" go back "<<"\n";
}

int query(int n, int l, int r, int x, int y, int phi)
{
    if(x<=l && r<=y)
        return segment[n + phi];
    
    int pivot = (l+r)>>1, rs=0;
    if(x <= pivot)
        rs = MAX(rs, query(l(n), l, pivot, x, y, phi));
    if(pivot < y)
        rs = MAX(rs, query(r(n), pivot+1, r, x, y, phi));
    return rs;
}

int main() {
    FAST;
    cin>>N>>M;
    REP2(i,N)
        cin>>A[i];
    REP(i,N-1)
    {
        int x,y;
        cin>>x>>y;
        //cout<<x<<" "<<y<<" \n";
        G[x].pb(y); G[y].pb(x);
    }
    //cout<<"end \n";
    // DFS AND BUILD PATHS
        lvl[1]=1;
        dfs(1); // build the paths;
        //cout<<"k = "<<K<<"\n";
        REP2(i, K)
        {
            reverse(P[i].begin(), P[i].end()); // reverse the paths so its starting with the lowest level node.
            if(i>1)
                position[i] = position[i-1] + 4*length[i-1]; // why is 4 is intelligible to me....
            build(1, 1, length[i], position[i], i);
            //cout<<"new \n";
        }
    // ----
    REP(i,M)
    {
        int t,x,y;
        cin>>t>>x>>y;
        
        //cout<<" doo for "<<t<<" "<<x<<" "<<y<<" \n"; 
        if(t==0)
        {
            update(1, 1, length[path[x]], lvl[x] - conn_lvl[path[x]], y, position[path[x]]);
        }
        else
        {
            int asd=0;
            int sol=0;
            while(1 && asd<10)
            {
                asd++;
                if(path[x] == path[y])
                {
                    //cout<<"path["<<x<<"] = path["<<y<<"]"<<"\n";
                    if(lvl[x] > lvl[y])
                        swap(x,y);
                    sol = MAX(sol, query(1, 1, length[path[x]], lvl[x]-conn_lvl[path[x]], lvl[y]-conn_lvl[path[x]], position[path[x]]));
                    break;
                }
                if(conn_lvl[path[x]] < conn_lvl[path[y]])
                    swap(x,y);
                
                sol = MAX(sol, query(1, 1, length[path[x]], 1, lvl[x] - conn_lvl[path[x]], position[path[x]]));
                
                //cout<<conn[path[x]]<<" ";
                x=conn[path[x]];
            }
            //cout<<"sol = ";
            cout<<sol<<"\n";
        
        }
    }
    return 0;
}