您的位置:首页 > 其它

fzu 2082 过路费(树链剖分,询问两点距离)

2014-08-12 21:59 441 查看
Problem 2082 过路费

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: