FZU 2082 过路费(树链剖分 边权)题解
题意:给出每条边权值,可以更新每条边权值,询问两个点路径的最小权值
思路:重链剖分边权化点权,让每个儿子节点继承边权。
插点权的时候比较边的两个节点的深度,插进儿子节点中。
代码:
#include<cmath> #include<set> #include<map> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include <iostream> #include<algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 50000 + 5; const int M = 50 + 5; const ull seed = 131; const int INF = 0x3f3f3f3f; const int MOD = 1000000007; int fa[maxn]; int top[maxn]; int sz[maxn]; int son[maxn]; int deep[maxn]; int dfn[maxn], tol; int fd[maxn]; int n, m; struct Edge{ int v, w, id, next; }edge[maxn << 1]; int head[maxn], tot; void init(){ memset(head, -1, sizeof(head)); tot = tol = 0; memset(son, -1, sizeof(son)); } void addEdge(int u, int v, int w, int id){ edge[tot].v = v; edge[tot].w = w; edge[tot].id = id; edge[tot].next = head[u]; head[u] = tot++; } void dfs1(int u, int pre, int d){ deep[u] = d; fa[u] = pre; sz[u] = 1; for(int i = head[u]; i != -1; i = edge[i].next){ int v = edge[i].v; if(v == pre) continue; dfs1(v, u, d + 1); sz[u] += sz[v]; if(son[u] == -1 || sz[v] > sz[son[u]]) son[u] = v; } } void dfs2(int u, int tp){ top[u] = tp; dfn[u] = ++tol; fd[tol] = u; if(son[u] == -1) return; dfs2(son[u], tp); for(int i = head[u]; i != -1; i = edge[i].next){ int v = edge[i].v; if(v != son[u] && v != fa[u]){ dfs2(v, v); } } } ll sum[maxn << 2]; void update(int pos, int l, int r, int v, int rt){ if(l == r){ sum[rt] = v; return; } int m = (l + r) >> 1; if(pos <= m) update(pos, l, m, v, rt << 1); else update(pos, m + 1, r, v, rt << 1 | 1); sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } ll query(int L, int R, int l, int r, int rt){ if(L <= l && R >= r){ return sum[rt]; } int m = (l + r) >> 1, ans = 0; if(L <= m) ans += query(L, R, l, m, rt << 1); if(R > m) ans += query(L, R, m + 1, r, rt << 1 | 1); sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; return ans; } ll change(int u, int v){ ll ret = 0; while(top[u] != top[v]){ if(deep[top[u]] < deep[top[v]]) swap(u, v); ret += query(dfn[top[u]], dfn[u], 1, n, 1); u = fa[top[u]]; } if(u == v) return ret; //!!! if(deep[u] > deep[v]) swap(u, v); ret += query(dfn[son[u]], dfn[v], 1, n, 1); return ret; } int e[maxn][3]; int main(){ while(~scanf("%d%d", &n, &m)){ init(); for(int i = 1; i <= n - 1; i++){ int u, v, w; scanf("%d%d%d", &u, &v, &w); addEdge(u, v, w, i); addEdge(v, u, w, i); e[i][0] = u, e[i][1] = v, e[i][2] = w; } dfs1(1, 0, 0); dfs2(1, 1); for(int i = 1; i <= n - 1; i++){ int fx = e[i][0], fy = e[i][1]; if(deep[fx] < deep[fy]) swap(fx, fy); update(dfn[fx], 1, n, e[i][2], 1); } while(m--){ int op, a, b; scanf("%d%d%d", &op, &a, &b); if(op == 0){ int fx = e[a][0], fy = e[a][1]; if(deep[fx] < deep[fy]) swap(fx, fy); update(dfn[fx], 1, n, b, 1); } else{ printf("%lld\n", change(a, b)); } } } return 0; }