SPOJ QTREE – Query on a tree

You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3…N-1.

We will ask you to perfrom some instructions of the following form:

  • CHANGE i ti : change the cost of the i-th edge to ti
    or
  • QUERY a b : ask for the maximum edge cost on the path from node a to node b

Input

The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.

For each test case:

  • In the first line there is an integer N (N <= 10000),
  • In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of cost c (c <= 1000000),
  • The next lines contain instructions “CHANGE i ti” or “QUERY a b”,
  • The end of each test case is signified by the string “DONE“.

There is one blank line between successive tests.

Output

For each “QUERY” operation, write one integer representing its result.

Example

Input:
1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Output:
1
3

为什么你剖分的那么熟练啊

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;

const int MAXN = 10010;
const int MAXE = 2 * MAXN;
const int INF = 0x7fffffff;

int head[MAXN], cost[MAXN], id[MAXN];
int weight[MAXE], to[MAXE], next[MAXE];
int n, ecnt;

inline void init() {
    memset(head, 0, sizeof(head));
    ecnt = 2;
}

inline void add_edge(int u, int v, int c) {
    to[ecnt] = v; weight[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
    to[ecnt] = u; weight[ecnt] = c; next[ecnt] = head[v]; head[v] = ecnt++;
}

int maxt[MAXN * 4];

void modify(int x, int left, int right, int a, int b, int val) {
    if(a <= left && right <= b) maxt[x] = val;
    else {
        int ll = x << 1, rr = ll ^ 1;
        int mid = (left + right) >> 1;
        if(a <= mid) modify(ll, left, mid, a, b, val);
        if(mid < b) modify(rr, mid + 1, right, a, b, val);
        maxt[x] = max(maxt[ll], maxt[rr]);
    }
}

int query(int x, int left, int right, int a, int b) {
    if(a <= left && right <= b) return maxt[x];
    else {
        int ll = x << 1, rr = ll ^ 1;
        int mid = (left + right) >> 1, ret = 0;
        if(a <= mid) ret = max(ret, query(ll, left, mid, a, b));
        if(mid < b) ret = max(ret, query(rr, mid + 1, right, a, b));
        return ret;
    }
}

int size[MAXN], fa[MAXN], dep[MAXN], son[MAXN];
int tid[MAXN], top[MAXN], dfs_clock;

void dfs_size(int u, int f, int depth) {
    fa[u] = f; dep[u] = depth;
    size[u] = 1; son[u] = 0;
    int maxsize = 0;
    for(int p = head[u]; p; p = next[p]) {
        int &v = to[p];
        if(v == f) continue;
        cost[v] = weight[p];
        dfs_size(v, u, depth + 1);
        size[u] += size[v];
        if(size[v] > maxsize) {
            maxsize = size[v];
            son[u] = v;
        }
    }
}

void dfs_heavy_edge(int u, int ancestor) {
    tid[u] = ++dfs_clock; top[u] = ancestor;
    modify(1, 1, n, tid[u], tid[u], cost[u]);
    if(son[u]) dfs_heavy_edge(son[u], ancestor);
    for(int p = head[u]; p; p = next[p]) {
        int &v = to[p];
        if(v == fa[u] || v == son[u]) continue;
        dfs_heavy_edge(v, v);
    }
}

int query(int x, int y) {
    int ret = 0;
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        ret = max(ret, query(1, 1, n, tid[top[x]], tid[x]));
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    ret = max(ret, query(1, 1, n, tid[x] + 1, tid[y]));
    return ret;
}

void change(int x, int y) {
    int u = to[x], v = to[x ^ 1];
    if(fa[u] == v) swap(u, v);
    modify(1, 1, n, tid[v], tid[v], y);
}

char str[15];

inline int readint() {
    char c = getchar();
    while(!isdigit(c)) c = getchar();
    int ret = 0;
    while(isdigit(c)) ret = ret * 10 + c - '0', c = getchar();
    return ret;
}

int main() {
    int T = readint();
    for(int t = 1; t <= T; ++t) {
        n = readint();
        init();
        for(int i = 1; i < n; ++i) {
            int u = readint(), v = readint(), c = readint();
            id[i] = ecnt;
            add_edge(u, v, c);
        }
        memset(maxt, 0, sizeof(maxt));
        dfs_size(1, 0, 0); cost[1] = -INF;
        dfs_clock = 0;
        dfs_heavy_edge(1, 1);
        while(scanf("%s", str) && *str != 'D') {
            int x = readint(), y = readint();
            if(*str == 'C') change(id[x], y);
            else printf("%d\n", query(x, y));
        }
    }
}

 

此条目发表在SPOJ, 树链剖分分类目录。将固定链接加入收藏夹。