poj2763(树链剖分

poj2763

题意

给定一个树形图,某人原来在 s 点,每条边(路)有通过的时间花费,有两种操作:1. 查询某人到 u 点花费的时间 2. 更新某条路的时间花费。

分析

权值在边上,可以把它们 “转移” 到点上,对于一条边,让 (dep) 最大的点存储权值,比如说我们要更新 ((u, v)) 这条路,如果 (dep[u] > dep[v]) ,更新 (u) 这个点对应的线段树的点即可。
将树映射到线段树上之后,本题就变成了单点更新,区间求和的线段树问题了。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
int n, q, s;
int fa[MAXN]; // fa[v]: v 的父亲
int dep[MAXN]; // dep[v]: v 的深度(根深度为1)
int siz[MAXN]; // : 以 v 为根的子树的节点数
int son[MAXN]; // : 重儿子,siz[u] 为 v 的子节点中 siz 值最大的,那么 u 就是 v 的重儿子
int top[MAXN]; // : 表示 v 所在的重链的顶端节点
int w[MAXN]; // : 表示 v 与其父亲节点的连边在线段树中的位置
int num; // 将树映射到线段树上的标号
int cnt, head[MAXN];
struct Edge {
    int to, next;
}edge[MAXN];
struct E {
    int u, v, c;
}e[MAXN];
void addedge(int u, int v) {
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}
void dfs(int u) {
    siz[u] = 1; son[u] = 0;
    for(int i = head[u]; ~i; i = edge[i].next) {
        if(edge[i].to != fa[u]) {
            fa[edge[i].to] = u;
            dep[edge[i].to] = dep[u] + 1;
            dfs(edge[i].to);
            if(siz[edge[i].to] > siz[son[u]]) son[u] = edge[i].to;
            siz[u] += siz[edge[i].to];
        }
    }
}
void build_tree(int u, int tp) {
    w[u] = ++num; top[u] = tp;
    if(son[u]) build_tree(son[u], top[u]); // 使重链各边在线段树中呈连续分布
    for(int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to;
        if(v != son[u] && v != fa[u])
            build_tree(v, v);
    }
}
ll sum[MAXN];
void pushUp(int rt) {
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void build(int l, int r, int rt) {
    sum[rt] = 0;
    if(l == r) return;
    int m = (l + r) / 2;
    build(lson); build(rson);
}
void update(int p, int c, int l, int r, int rt) {
    if(l == r) {
        sum[rt] = c;
        return;
    }
    int m = (l + r) / 2;
    if(m >= p) update(p, c, lson);
    else update(p, c, rson);
    pushUp(rt);
}
ll query(int L, int R, int l, int r, int rt) {
    if(L <= l && R >= r) return sum[rt];
    int m = (l + r) / 2;
    ll res = 0;
    if(m >= L) res += query(L, R, lson);
    if(m < R) res += query(L, R, rson);
    return res;
}
void change(int v, int c) {
    if(dep[e[v].u] > dep[e[v].v]) update(w[e[v].u], c, 1, n, 1);
    else update(w[e[v].v], c, 1, n, 1);
}
ll seek(int v, int u) {
    int t1 = top[v], t2 = top[u];
    ll res = 0;
    while(t1 != t2) {
        if(dep[t1] < dep[t2]) {
            swap(t1, t2); swap(v, u);
        }
        res += query(w[t1], w[v], 1, n, 1);
        v = fa[t1]; t1 = top[v];
    }
    if(v == u) return res;
    if(dep[v] > dep[u]) swap(v, u);
    return res + query(w[son[v]], w[u], 1, n, 1);
}
int main() {
    memset(head, -1, sizeof head);
    cnt = num = 0;
    scanf("%d%d%d", &n, &q, &s);
    for(int i = 1;  i < n; i++) {
        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].c);
        addedge(e[i].u, e[i].v);
        addedge(e[i].v, e[i].u);
    }
    dfs(1);
    build_tree(1, 1);
    build(1, n, 1);
    for(int i = 1; i < n; i++) {
        if(dep[e[i].u] > dep[e[i].v]) update(w[e[i].u], e[i].c, 1, n, 1);
        else update(w[e[i].v], e[i].c, 1, n, 1);
    }
    while(q--) {
        int cc;
        int x, y;
        scanf("%d", &cc);
        if(cc) {
            scanf("%d%d", &x, &y);
            change(x, y);
        } else {
            scanf("%d", &x);
            printf("%lld
", seek(s, x));
            s = x;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ftae/p/7203332.html