Cod sursa(job #1793749)

Utilizator andrei.arnautuAndi Arnautu andrei.arnautu Data 31 octombrie 2016 15:05:03
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 6.25 kb
/**
  *  Worg
  */
#include <cstdio>
#include <vector>

#define leftSon (node << 1)
#define rightSon ((node << 1) + 1)

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

const int MAX_N = 1 + 100000;
const int bufferDim = 100000;

/*-------- Input reader --------*/
class inputReader {
private:
        char buffer[bufferDim];
        int pos = 0;

        bool digit(char c) {
            return('0' <= c && c <= '9');
        }
public:
        void getBuffer() {
            fread(buffer, 1, bufferDim, stdin);
            pos = 0;
        }

        void operator >>(int &nr) {
            nr = 0;
            while(!digit(buffer[pos]))
                if(++ pos == bufferDim)
                    getBuffer();
            while(digit(buffer[pos])) {
                nr = nr * 10 + buffer[pos] - '0';
                if(++ pos == bufferDim)
                    getBuffer();
            }
        }
} cin;

/*-------- Input data --------*/
int N, M;
/*-------- Heavy path data --------*/
struct STree;
struct Node;
struct Chain;

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

struct Chain {
    Node* father;
    vector< Node* > nodes;
    vector< int > maxValue;
    bool ok;
    int delay, maxDepth;

    Chain() {
        this->ok = false;
    }
};

Node graph[MAX_N];
/*-------- --------*/

void readInput() {
    cin.getBuffer();
    cin >> N; cin >> M;
    for(int i = 1; i <= N; i++) {
        cin >> graph[i].value;
        graph[i].index = i;
    }
    for(int i = 1; i < N; i++) {
        int a, b; cin >> a; cin >> b;
        graph[a].adjacentNodes.push_back(&graph[b]);
        graph[b].adjacentNodes.push_back(&graph[a]);
    }
}

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

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

    if(sonWeight == 0) {
        /* daca nodul e frunza, atunci creem un nou lant pentru el */
        node->chain = new Chain();
    } else {
        /* altfel, adaugam nodul curent la lantul cel mai greu din subarbore */
        node->chain = son->chain;
        for(Node *nxt : node->adjacentNodes) {
            if(dad != nxt->index && son->index != nxt->index) {
                /* nodul curent va deveni tatal celorlalte lanturi din subarbore de care nu apartine */
                nxt->chain->father = node;
            }
        }
    }
    /* adaugam nodul la lista lantului
       De sesizat ca pentru fiecare lant nodurile sunt introduse de jos in sus */
    node->chain->nodes.push_back(node);
}

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

        maxValue[node] = max(maxValue[leftSon], maxValue[rightSon]);
    }
}

void makeSegmentTrees() {
    for(int i = 1; i <= N; i++) {
        Chain* chain = graph[i].chain;
        if(chain->ok == false) {
            int Space = (int)chain->nodes.size() + 1;
            chain->maxValue.reserve(Space << 2);
            chain->ok = true;

            Node* node = chain->nodes.back();
            chain->delay = node->depth - 1;

            node = chain->nodes[0];
            chain->maxDepth = node->depth;

            for(Node* node : chain->nodes) {
                Update(chain->maxValue, 1, 1, chain->maxDepth - chain->delay, node->depth - chain->delay, node->value);
            }
        }
    }
}

void Query(vector< int > &maxValue, int node, int left, int right, int first, int last, int &Answer) {
    if(first <= left && right <= last) {
        Answer = max(Answer, maxValue[node]);
    } else {
        int mid = (left + right) >> 1;
        if(first <= mid) {
            Query(maxValue, leftSon, left, mid, first, last, Answer);
        }
        if(mid < last) {
            Query(maxValue, rightSon, mid + 1, right, first, last, Answer);
        }
    }
}

int getQueryAnswer(Node *u, Node *v) {
    int queryAnswer = 0;

    if(u->chain == v->chain) {
        Chain *chain = u->chain;
        Query(u->chain->maxValue, 1, 1, chain->maxDepth - chain->delay, min(u->depth, v->depth) - chain->delay, max(u->depth, v->depth) - chain->delay, queryAnswer);
    } else {
        int H1 = u->chain->father->depth;
        int H2 = v->chain->father->depth;

        if(H1 < H2) {
            Chain *chain = v->chain;
            Query(chain->maxValue, 1, 1, chain->maxDepth - chain->delay, 1, v->depth - chain->delay, queryAnswer);
            queryAnswer = max(queryAnswer, getQueryAnswer(u, chain->father));
        } else {
            Chain *chain = u->chain;
            Query(chain->maxValue, 1, 1, chain->maxDepth - chain->delay, 1, u->depth - chain->delay, queryAnswer);
            queryAnswer = max(queryAnswer, getQueryAnswer(chain->father, v));
        }
    }

    return queryAnswer;
}

void solveOperations() {
    for(int i = 1; i <= M; i++) {
        int t, x, y;
        cin >> t; cin >> x; cin >> y;

        if(t == 0) {
            /* avem un update */
            graph[x].value = y;
            Chain* chain = graph[x].chain;
            Update(chain->maxValue, 1, 1, chain->maxDepth - chain->delay, graph[x].depth - chain->delay, graph[x].value);
        } else {
            /* avem un query */
            int Solution = getQueryAnswer(&graph[x], &graph[y]);
            printf("%d\n", Solution);
        }
    }
}

int main() {
    readInput();
    DFS(&graph[1]);
    graph[0].depth = 0; graph[1].chain->father = &graph[0];
    makeSegmentTrees();
    solveOperations();
    return 0;
}