Cod sursa(job #1947975)

Utilizator andrei.arnautuAndi Arnautu andrei.arnautu Data 31 martie 2017 16:06:37
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.43 kb
/**
  *  Worg
  */
#include <cstdio>
#include <vector>
#include <algorithm>

using std::vector;
FILE *fin = freopen("heavypath.in", "r", stdin);
FILE *fout = freopen("heavypath.out", "w", stdout);

const int kMaxN = 1 + 100000;

/*-------- Structures --------*/
struct Chain;
struct Node;

struct Node {
    int index, depth, weight, value;
    vector<Node* > adj_nodes;
    Chain *chain;
};

struct Chain {
    Node *father;
    vector<Node* > nodes;
    vector<int > arbint;
    int delay, max_depth;

    bool ok;
    Chain() {this->ok = false;}
};
/*-------- Input data --------*/
int N, M;
Node graph[kMaxN];
/*-------- Chain data --------*/

/*-------- --------*/

void ReadInput() {
    scanf("%d%d", &N, &M);
    for(int i = 1; i <= N; i++) {
        scanf("%d", &graph[i].value);
        graph[i].index = i;
    }
    for(int i = 2; i <= N; i++) {
        int a, b; scanf("%d%d", &a, &b);
        graph[a].adj_nodes.push_back(&graph[b]);
        graph[b].adj_nodes.push_back(&graph[a]);
    }
}

void DFS(Node *node, int depth = 1, int dad = 0) {
    node->depth = depth;
    node->weight = 1;

    Node *son;
    int son_weight = 0;
    for(Node *nxt : node->adj_nodes) {
        if(nxt->index != dad) {
            DFS(nxt, depth + 1, node->index);
            node->weight += nxt->weight;
            if(nxt->weight > son_weight) {
                son_weight = nxt->weight;
                son = nxt;
            }
        }
    }

    if(son_weight == 0) {  //  Nodul este frunza, deci creem un lant nou
        node->chain = new Chain();
    } else {  //  Adaugam nodul curent la lantul celui mai greu fiu din subarbore
        node->chain = son->chain;
        for(Node *nxt : node->adj_nodes) {
            if(nxt->index != dad && nxt->index != son->index) {
                nxt->chain->father = node;
            }
        }
    }
    //  Adaugam nodul la lant
    node->chain->nodes.push_back(node);
}

void Update(vector<int > &arbint, int node, int left, int right, int pos, int value) {
    arbint[node] = 0;
    if(left == right) {
        arbint[node] = value;
    } else {
        int mid = (left + right) >> 1;
        int left_son = node << 1;
        int right_son = left_son + 1;

        if(pos <= mid) {
            Update(arbint, left_son, left, mid, pos, value);
        } else {
            Update(arbint, right_son, mid + 1, right, pos, value);
        }
        arbint[node] = std::max(arbint[left_son], arbint[right_son]);
    }
}

void Query(vector<int > &arbint, int node, int left, int right, int first, int last, int &answer) {
    if(first <= left && right <= last) {
        answer = std::max(answer, arbint[node]);
    } else {
        int mid = (left + right) >> 1;
        int left_son = node << 1;
        int right_son = left_son + 1;

        if(first <= mid) {
            Query(arbint, left_son, left, mid, first, last, answer);
        }
        if(mid < last) {
            Query(arbint, right_son, mid + 1, right, first, last, answer);
        }
    }
}

void ConstructArbints() {
    for(int i = 1; i <= N; i++) {
        Chain *chain = graph[i].chain;
        if(!chain->ok) {  //  Daca nu am construit deja arborele de intervale pentru lantul curent
            int space_needed = (int)chain->nodes.size() + 1;
            chain->arbint.reserve(space_needed << 2);
            chain->ok = true;

            //  Calculam max_depth si delay. Nodurile sunt introduse in lista de jos in sus
            chain->delay = chain->nodes.back()->depth - 1;
            chain->max_depth = chain->nodes[0]->depth;

            //  Construim arborele de intervale
            for(Node *node : chain->nodes) {
                Update(chain->arbint, 1, 1, chain->max_depth - chain->delay, node->depth - chain->delay, node->value);
            }

        }
    }
}

int GetQueryAnswer(Node *u, Node *v) {
    int query_answer = 0;
    if(u->chain == v->chain) {
        Chain *chain = u->chain;
        Query(chain->arbint, 1, 1, chain->max_depth - chain->delay, std::min(u->depth, v->depth) - chain->delay, std::max(u->depth, v->depth) - chain->delay, query_answer);
    } else {
        int h1 = u->chain->father->depth;
        int h2 = v->chain->father->depth;

        if(h1 < h2) {
            Chain *chain = v->chain;
            Query(chain->arbint, 1, 1, chain->max_depth - chain->delay, 1, v->depth - chain->delay, query_answer);
            query_answer = std::max(query_answer, GetQueryAnswer(u, chain->father));
        } else {
            Chain *chain = u->chain;
            Query(chain->arbint, 1, 1, chain->max_depth - chain->delay, 1, u->depth - chain->delay, query_answer);
            query_answer = std::max(query_answer, GetQueryAnswer(chain->father, v));
        }
    }

    return query_answer;
}

void ProcessOperations() {
    for(int i = 1; i <= M; i++) {
        int type, x, y; scanf("%d%d%d", &type, &x, &y);
        if(type == 0) {
            graph[x].value = y;
            Chain *chain = graph[x].chain;
            Update(chain->arbint, 1, 1, chain->max_depth - chain->delay, graph[x].depth - chain->delay, graph[x].value);
        } else {
            printf("%d\n", GetQueryAnswer(&graph[x], &graph[y]));
        }
    }
}

int main() {
    ReadInput();
    DFS(&graph[1]);
    graph[0].depth = 0; graph[1].chain->father = &graph[0];
    ConstructArbints();
    ProcessOperations();

    return 0;
}