Cod sursa(job #1820218)

Utilizator andreicoman299Coman Andrei andreicoman299 Data 1 decembrie 2016 13:25:02
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.23 kb
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <utility>
#include <algorithm>

#define BUF_SIZE 1<<17
char buffer[BUF_SIZE];
int pbuf = BUF_SIZE;
FILE *fi, *fo;
inline char nextch(){
    if(pbuf == BUF_SIZE){
        fread(buffer, BUF_SIZE, 1, fi);
        pbuf=0;
    }
    return buffer[pbuf++];
}
inline long long nextnum(){
    long long a = 0;
    char c = nextch();
    while((c < '0' || c > '9') && c != '-')
        c = nextch();
    int semn = 1;
    if(c == '-'){
        semn = -1;
        c = nextch();
    }
    while('0' <= c && c <= '9'){
        a = a*10+c-'0';
        c = nextch();
    }
    return a*semn;
}
inline int maxim(int a, int b){
    return a > b ? a : b;
}

#define MAXN 100000
#define MAXM 100000

int n, m;

struct query{
    int type;
    int val1;
    int val2;
};
query operation[1 + MAXM];

int subTreeDim[1 + MAXN];
int level[1 + MAXN];
int used[1 + MAXN];
int v[1 + MAXN];
std::vector < int > G[1 + MAXN];

int aint[4 * MAXN];

int numPaths = 0;
int p[1+MAXN];
int pathDim[1+MAXN];
int pathFather[1+MAXN];
int pathLevel[1+MAXN];
int pathPosition[1+MAXN];
std::vector < int > path[1+MAXN];

void dfs (int node){
    used[node] = 1;
    subTreeDim[node] = 1;
    int isLeaf = 1;
    int nodeSubMax=-1;

    for(int i = 0; i <G[node].size(); i++){
        int son = G[node][i];
        if(!used[son]){
            isLeaf = 0;
            level[son] = level[node] + 1;

            dfs(son);
            subTreeDim[node] += subTreeDim[son];

            if(nodeSubMax == -1)
                nodeSubMax = son;
            else if(subTreeDim[nodeSubMax] < subTreeDim[son])
                nodeSubMax = son;}}

    if(isLeaf){
        p[node] = ++numPaths;
        pathDim[numPaths] = 1;
        path[numPaths].push_back(node);}
    else{
        p[node] = p[nodeSubMax];
        pathDim[p[node]]++;
        path[p[node]].push_back(node);

        for(int i = 0; i < G[node].size(); i++){
            if(G[node][i] != nodeSubMax && level[G[node][i]] >= level[node]){
                pathFather[p[G[node][i]]] = node;
                pathLevel[p[G[node][i]]] = level[node];}}}
}

inline void buildAint(int node, int left, int right, int delay, int currPath){
    if(left == right)
        aint[node + delay] = v[path[currPath][left - 1]];
    else{
        int m = (left + right)/2;
        buildAint(2 * node, left, m, delay, currPath);
        buildAint(2 * node+1, m+1, right, delay, currPath);

        aint[node + delay] = maxim(aint[2 * node + delay], aint[2 * node + 1 + delay]);}
}

inline void createPath(){
    level[1]=1;
    dfs(1);

    for(int i = 1; i <= numPaths; i++){
        reverse(path[i].begin(), path[i].end());

        if(i > 1)
            pathPosition[i] = pathPosition[i-1] + pathDim[i-1] * 4;

        buildAint(1, 1, pathDim[i], pathPosition[i], i);}

}

void update(int node, int left, int right, int poz, int val, int delay){
    if(left == right)
        aint[node + delay] = val;
    else{
        int m = (left + right)/2;
        if(poz <= m) update(2 * node, left, m, poz, val, delay);
        else update(2 * node + 1, m + 1, right, poz, val, delay);

        aint[node + delay] = maxim(aint[2 * node +delay], aint[2 * node + 1 +delay]);}
}

int query(int node, int left, int right, int qleft, int qright, int delay){
    if(qleft <= left && right <= qright)
        return aint[node + delay];
    else{
        int m = (left + right)/2;
        int rez = 0;
        if(qleft <= m) rez = maxim(rez, query(2 * node, left, m, qleft, qright, delay));
        if(m < qright) rez = maxim(rez, query(2 * node + 1, m + 1, right, qleft, qright, delay));
        return rez;}

}

int main(){
    fi = fopen("heavypath.in","r");
    fo = fopen("heavypath.out","w");

    n = nextnum();
    m = nextnum();
    for(int i = 1; i <=n; i++)
        v[i] = nextnum();

    for(int i = 1; i < n; i++){
        int a = nextnum(), b = nextnum();
        G[a].push_back(b);
        G[b].push_back(a);}

    for(int i = 1; i <= m; i++){
        operation[i].type = nextnum();
        operation[i].val1 = nextnum();
        operation[i].val2 = nextnum();}

    createPath();
    pathLevel[p[1]] = 0;
    pathFather[p[1]] = 0;

    for(int i = 1; i <=m; i++){
        int x = operation[i].val1, y = operation[i].val2;
        if(operation[i].type == 0)
            update(1, 1, pathDim[p[x]], level[x] - pathLevel[p[x]], y, pathPosition[p[x]]);
        else{
            int sol = 0;
            int flag = 1;
            while(flag){
                if(p[x] == p[y]){
                    if(level[x] > level[y])
                        std::swap(x, y);
                    sol = maxim(sol, query(1, 1, pathDim[p[x]], level[x] - pathLevel[p[x]], level[y] - pathLevel[p[x]], pathPosition[p[x]]));
                    flag = 0;}
                else{
                    if(pathLevel[p[x]] < pathLevel[p[y]])
                        std::swap(x, y);
                    sol = maxim(sol, query(1, 1, pathDim[p[x]], 1, level[x] - pathLevel[p[x]], pathPosition[p[x]]));
                    x=pathFather[p[x]];}}
            fprintf(fo,"%d\n", sol);}
    }
    fclose(fi);
    fclose(fo);
    return 0;
}