spoj375 Query on a tree 树链剖分

题目大意

给一棵树,有两种操作,一种是改变某一条边的边权,一种是询问某两个结点间的路径的最大值

解题

具体思路参见2009年集训队漆子超的论文《分治算法在树的路径问题中的应用》
树链剖分裸题,无奈昨天一直TLE,非常怨念,今天重写了一发,居然A了,虽然也不快,3.89s
感觉我用的姿势应该是能看得下去的……

CODE

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 10010;
const int inf = 0x3fffffff;

int max(int a, int b) {
    return a > b ? a : b;
}

struct edge {
    int v, next;
    edge() {}
    edge(int a, int b) : v(a), next(b) {}
};
edge e[maxn*3];

struct data {
    int x, y, d;
};
data E[maxn<<1];

int head[maxn], son[maxn], sz[maxn], pre[maxn], top[maxn], dep[maxn], hash[maxn];
int n, num, tot;

void add(int u, int v) {
    e[tot] = edge(v, head[u]); head[u] = tot++;
    e[tot] = edge(u, head[v]); head[v] = tot++;
}

void dfs(int u, int d) {
    sz[u] = 1; son[u] = 0; dep[u] = d;
    for (int i = head[u]; ~i; i = e[i].next) {
        int v = e[i].v;
        if (v == pre[u]) continue;
        pre[v] = u;
        dfs(v, d+1);
        sz[u] += sz[v];
        if (sz[v] > sz[son[u]]) son[u] = v;
    }
}

void build_tree(int u, int fa) {
    hash[u] = ++num; top[u] = fa;
    if (son[u]) build_tree(son[u], top[u]);
    for (int i = head[u]; ~i; i = e[i].next) {
        int v = e[i].v;
        if (v == pre[u] || v == son[u]) continue;
        build_tree(v, v);
    }
}

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1

int mx[maxn<<2];

void PushUp(int rt) {
    mx[rt] = max(mx[rt<<1], mx[rt<<1|1]);
}

void build(int l, int r, int rt) {
    mx[rt] = -inf;
    if (l == r) return;
    int m = (l+r) >> 1;
    build(lson); build(rson);
}

void update(int pos, int x, int l, int r, int rt) {
    if (l == r) {
        mx[rt] = x;
        return;
    }
    int m = (l+r) >> 1;
    if (pos <= m) update(pos, x, lson);
    else update(pos, x, rson);
    PushUp(rt);
}

int query(int ll, int rr, int l, int r, int rt) {
    if (ll <= l && rr >= r) return mx[rt];
    int m = (l+r) >> 1;
    int res = -inf;
    if (ll <= m) res = max(res, query(ll, rr, lson));
    if (rr > m) res = max(res, query(ll, rr, rson));
    return res;
}

int Query(int x, int y) {
    int ans = -inf;
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        ans = max(ans, query(hash[top[x]], hash[x], 2, n, 1));
        x = pre[top[x]];
    }
    if (dep[x] > dep[y]) swap(x, y);
    if (x != y)
        ans = max(ans, query(hash[x]+1, hash[y], 2, n, 1));
    return ans;
}

void solve() {
    scanf("%d", &n);
    memset(head, -1, sizeof(head));
    tot = 0;
    for (int i = 1; i < n; i++) {
        scanf("%d%d%d", &E[i].x, &E[i].y, &E[i].d);
        add(E[i].x, E[i].y);
    }
    sz[0] = 0; num = 0;
    dfs(1, 1);
    build_tree(1, 1);
    build(2, n, 1);
    for (int i = 1; i < n; i++) {
        if (dep[E[i].x] < dep[E[i].y]) swap(E[i].x, E[i].y);
        update(hash[E[i].x], E[i].d, 2, n, 1);
    }
    char op[10];
    while (1) {
        scanf("%s", op);
        if (op[0] == 'D') break;
        int x, y;
        scanf("%d%d", &x, &y);
        if (op[0] == 'C') update(hash[E[x].x], y, 2, n, 1);
        else if (op[0] == 'Q') printf("%d\n", Query(x, y));
    }
}

int main() {
    int cs; scanf("%d", &cs);
    while (cs--) solve();
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值