[spoj QTREE Query on a tree]树链剖分

[spoj QTREE Query on a tree]树链剖分

题目链接[spoj QTREE Query on a tree]
题意描述:给定一棵顶点数为N的带权树。有Q次操作,每次操作或者改变第 i 条边的权值,或者查询顶点u v 的路径上面的最长边。
解题思路
树链剖分的入门题。今天比较系统的学习了一下树链剖分。其实树链剖分就是将树上的边(点)映射到若干条连续的线段上。然后结合一下线段树等数据结构,就可以在O(log(n))的时间内完成对边(点)权值的修改,统计权值求和,统计权值最值等的操作。
比较关键的就是如何将树上的边(点)映射到若干条连续的线段上。——求出所有的重链,然后每条重链就构成了一条线段。
树剖原理请参考:ACdreamers 的 《树链剖分原理

#include <bits/stdc++.h>
using namespace std;

#define FIN         freopen("input.txt", "r", stdin)
#define lson        l, mid, (rt << 1)
#define rson        mid + 1, r, (rt << 1 | 1)
#define __mid__     int mid = (l + r) >> 1

typedef long long LL;
const int MAXN = 10000 + 5;

int T, N;

struct Edge {
    int v, next;
    Edge() {}
    Edge(int v, int next) : v(v), next(next) {}
} edge[MAXN << 1];
int head[MAXN], ESZ, E[MAXN][3];
int siz[MAXN], top[MAXN], fa[MAXN], son[MAXN], dep[MAXN], tid[MAXN], rk[MAXN], id;
int seg[MAXN * 3];
void init() {
    ESZ = 0;
    id = 0;
    memset(head, -1, sizeof(head));
    memset(son, -1, sizeof(son));
}
void add_edge(int u, int v) {
    edge[ESZ] = Edge(v, head[u]);
    head[u] = ESZ ++;
}
void dfs1(int u, int pre, int k) {
    int v;
    siz[u] = 1;
    fa[u] = pre;
    dep[u] = k;
    for(int i = head[u]; ~i; i = edge[i].next) {
        v = edge[i].v;
        if(v == pre) continue;
        dfs1(v, u, k + 1);
        siz[u] += siz[v];
        if(son[u] == -1 || siz[son[u]] < siz[v]) son[u] = v;
    }
}
void dfs2(int u, int tp) {
    int v;
    tid[u] = ++ id;
    rk[tid[u]] = u;
    top[u] = tp;
    if(son[u] == -1) return;
    dfs2(son[u], tp);
    for(int i = head[u]; ~i; i = edge[i].next) {
        v = edge[i].v;
        if(v == fa[u] || v == son[u]) continue;
        dfs2(v, v);
    }
}
inline void pushUp(const int& rt) {
    seg[rt] = max(seg[rt << 1], seg[rt << 1 | 1]);
}
void update(const int& p, const int& v, int l, int r, int rt) {
    if(l == r) {
        seg[rt] = v;
        return;
    }
    __mid__;
    if(p <= mid) update(p, v, lson);
    else update(p, v, rson);
    pushUp(rt);
}
int query(const int& L, const int& R, int l, int r, int rt) {
    if(L <= l && r <= R) {
        return seg[rt];
    }
    __mid__;
    int ret = 0;
    if(L <= mid) ret = query(L, R, lson);
    if(R > mid) ret = max(ret, query(L, R, rson));
    return ret;
}
int getAns(int u, int v) {
    int ret = 0, f1 = top[u], f2 = top[v];
    while(f1 != f2) {
        if(dep[f1] < dep[f2]) {
            swap(u, v);
            swap(f1, f2);
        }
        ret = max(ret, query(tid[f1], tid[u], 1, id, 1));
        u = fa[f1], f1 = top[u];
    }
    if(u == v) return ret;
    if(dep[u] > dep[v]) swap(u, v);
    return max(ret, query(tid[son[u]], tid[v], 1, id, 1));
}

char op[15];
int main() {
#ifndef ONLINE_JUDGE
    FIN;
#endif // ONLINE_JUDGE
    int u, v, w, e;
    scanf("%d", &T);
    while(T --) {
        init();
        scanf("%d", &N);
        for(int i = 1; i <= N - 1; i ++) {
            scanf("%d %d %d", &u, &v, &w);
            E[i][0] = u, E[i][1] = v, E[i][2] = w;
            add_edge(u, v);
            add_edge(v, u);
        }
        dfs1(1, -1, 1);
        dfs2(1, 1);
        for(int i = 1; i <= N - 1; i ++) {
            if(dep[E[i][0]] > dep[E[i][1]]) swap(E[i][0], E[i][1]);
            update(tid[E[i][1]], E[i][2], 1, id, 1);
        }
        update(tid[1], -1, 1, id, 1);
        while(scanf("%s", op) == 1) {
            if(op[0] == 'D') break;
            if(op[0] == 'C') {
                scanf("%d %d", &e, &w);
                update(tid[E[e][1]], w, 1, id, 1);
            } else {
                scanf("%d %d", &u, &v);
                printf("%d\n", getAns(u, v));
            }
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值