fzu 2082 过路费(树链剖分,询问两点距离)
2014-08-12 21:59
441 查看
Problem 2082 过路费
Accept: 158 Submit: 630
有n座城市,由n-1条路相连通,使得任意两座城市之间可达。每条路有过路费,要交过路费才能通过。每条路的过路费经常会更新,现问你,当前情况下,从城市a到城市b最少要花多少过路费。
有多组样例,每组样例第一行输入两个正整数n,m(2 <= n<=50000,1<=m <= 50000),接下来n-1行,每行3个正整数a b c,(1 <= a,b <= n , a != b , 1 <= c <= 1000000000).数据保证给的路使得任意两座城市互相可达。接下来输入m行,表示m个操作,操作有两种:一. 0 a b,表示更新第a条路的过路费为b,1 <= a <= n-1 ; 二. 1 a b , 表示询问a到b最少要花多少过路费。
对于每个询问,输出一行,表示最少要花的过路费。
2 31 2 11 1 20 1 21 2 1
12
思路:树链剖分,线段树维护区间和
AC代码:
Accept: 158 Submit: 630
Time Limit: 1000 mSec Memory Limit : 32768 KB
Problem Description
有n座城市,由n-1条路相连通,使得任意两座城市之间可达。每条路有过路费,要交过路费才能通过。每条路的过路费经常会更新,现问你,当前情况下,从城市a到城市b最少要花多少过路费。
Input
有多组样例,每组样例第一行输入两个正整数n,m(2 <= n<=50000,1<=m <= 50000),接下来n-1行,每行3个正整数a b c,(1 <= a,b <= n , a != b , 1 <= c <= 1000000000).数据保证给的路使得任意两座城市互相可达。接下来输入m行,表示m个操作,操作有两种:一. 0 a b,表示更新第a条路的过路费为b,1 <= a <= n-1 ; 二. 1 a b , 表示询问a到b最少要花多少过路费。
Output
对于每个询问,输出一行,表示最少要花的过路费。
Sample Input
2 31 2 11 1 20 1 21 2 1
Sample Output
12思路:树链剖分,线段树维护区间和
AC代码:
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #define ll long long using namespace std; const int INF = 1e9; const int maxn = 100005; struct Edge { int v, next; } et[maxn * 2]; ll tree[maxn * 4]; int n, m, z, num, root; int d[maxn][2]; ll e[maxn]; int eh[maxn], dep[maxn], w[maxn], fa[maxn], top[maxn], son[maxn], siz[maxn]; void init() { root = (n + 1) / 2; fa[root] = z = dep[root] = num = 0; memset(siz, 0, sizeof(siz)); memset(tree, 0, sizeof(tree)); memset(eh, -1, sizeof(eh)); } void add(int u, int v) { Edge e = {v, eh[u]}; et[num] = e; eh[u] = num++; } void dfs(int u) { siz[u] = 1; son[u] = 0; for(int i = eh[u]; i != -1; i = et[i].next) { int v = et[i].v; if(v == fa[u]) continue; fa[v] = u; dep[v] = dep[u] + 1; dfs(v); if(siz[v] > siz[son[u]]) son[u] = v; siz[u] += siz[v]; } } void build_tree(int u, int tp) { w[u] = ++z; top[u] = tp; if(son[u]) build_tree(son[u], top[u]); for(int i = eh[u]; i != -1; i = et[i].next) { int v = et[i].v; if(v != son[u] && v != fa[u]) build_tree(v, v); } } void update(int rt, int l, int r, int loc, ll x) { if(loc > r || l > loc) return; if(l == r) { tree[rt] += x; return; } int mid = (l + r) >> 1, ls = rt * 2, rs = ls + 1; update(ls, l, mid, loc, x); update(rs, mid + 1, r, loc, x); tree[rt] = tree[ls] + tree[rs]; } ll sum(int rt, int left, int right, int l, int r) { if(l > right || r < left) return 0; if(l <= left && right <= r) return tree[rt]; int mid = (left + right) >> 1, ls = rt * 2, rs = ls + 1; return sum(ls, left, mid, l, r) + sum(rs, mid + 1, right, l, r); } inline ll find(int u, int v) { int f1 = top[u], f2 = top[v]; ll tmp = 0; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(f1, f2); swap(u, v); } tmp += sum(1, 1, z, w[f1], w[u]); u = fa[f1]; f1 = top[u]; } if(u == v) return tmp; if(dep[u] > dep[v]) swap(u, v); return tmp + sum(1, 1, z, w[son[u]], w[v]); } int main() { int a, b, op; ll c; while(~scanf("%d%d", &n, &m)) { init(); for(int i = 0; i < n - 1; i++) { scanf("%d%d%I64d", &a, &b, &c); add(a, b); add(b, a); d[i][0] = a, d[i][1] = b, e[i] = c; } dfs(root); build_tree(root, root); for(int i = 0; i < n - 1; i++) { if(dep[d[i][0]] > dep[d[i][1]]) swap(d[i][0], d[i][1]); update(1, 1, z, w[d[i][1]], e[i]); } while(m--) { scanf("%d", &op); if(!op) { scanf("%d%I64d", &a, &c); update(1, 1, z, w[d[a - 1][1]], c - e[a - 1]); e[a - 1] = c; } else { scanf("%d%d", &a, &b); printf("%I64d\n", find(a, b)); } } } return 0; }
相关文章推荐
- FZU 2082 过路费 树链剖分
- FZU 2082 过路费 树链剖分
- FZU2082 过路费(树链剖分线段树)
- fzu2082 过路费 树链剖分
- FZU 2082 过路费 (树链剖分)
- fzu 2082 过路费(树链剖分)
- FZU 2082 过路费(树链剖分)
- Fzu 2082 过路费【树链剖分--边操作】模板记录
- FZU 2082 过路费(树链剖分,边权)
- FZU 2082 过路费 树链剖分水题
- fzu 2082 过路费(树链剖分,单点更新+区间求和)
- FZU 2082 求树上任意点间距离 边权转为点权 树链剖分
- 【树链剖分】 FZU 2082 过路费
- fzu 2082 过路费(树链剖分)
- 【树链剖分】FZU 2082 过路费 求和
- FZU 2082 过路费(树链剖分)
- FZU 2082 过路费 [树链剖分]
- FZU - 2082:过路费(树链剖分)
- FZU 2082 过路费 (树链剖分)边权
- fzu Problem 2082 过路费 树链剖分 LCT 动态树