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
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <iostream>
#include <algorithm>
#define lson l,mid,o<<1
#define rson mid+1,r,o<<1|1
using namespace std;
const int maxn = 500005;
int son[maxn]; //表示该点重链的子节点
int num[maxn]; //表示以该点为根的子树的节点数量
int dep[maxn]; //表示该节点的深度
int fa[maxn]; // 表示该节点的父亲节点
int vis[maxn]; // 表示该节点在线段树中的编号
int top[maxn]; // 表示这条重链的顶端节点
int now;
int edge[maxn][3]; //保存所有的边
int head[maxn],cnt;
int n,m;
struct Edge
{
int v,next;
}e[150005];
void add(int a,int b)
{
e[cnt].v = b;
e[cnt].next = head[a];
head[a] = cnt++;
}
void init()
{
memset(head,-1,sizeof(head));
cnt = now = 0;
memset(son,-1,sizeof(son));
}
void dfs1(int u,int v,int step) //第一遍dfs求出son,fa,num,dep
{
dep[v] = step;
num[v] = 1;
fa[v] = u;
int i;
for(i = head[v]; i != -1; i = e[i].next)
{
int end = e[i].v;
if(end == u)
continue;
dfs1(v,end,step+1);
if(son[v] == -1 || num[son[v]] < num[end]) // 取子节点数量最多的点
{
son[v] = end;
}
num[v] += num[end];
}
}
void dfs2(int u,int v) // 第二遍dfs求出top和vis
{
top[v] = u;
vis[v] = now++; //编号为1的节点不表示边,每条边取深度比较深的那个点为线段树中的一个节点
if(son[v] != -1) //将重链在线段树里连续编号
{
dfs2(u,son[v]);
}
else
return;
int i;
for(i = head[v]; i != -1; i = e[i].next)
{
int end = e[i].v;
if(end == fa[v] || end == son[v]) //等于父亲节点或者等于重链的子节点跳过,这里的u不是父亲节点,是重链的顶端
continue;
dfs2(end,end); // 所有轻链重新为其节点的重链编号
}
}
int A,B;
int sum[maxn << 2];
void update(int l,int r,int o)
{
if(l == r)
{
sum[o] = B;
return;
}
int mid = (l + r) >> 1;
if(mid >= A) update(lson);
else update(rson);
sum[o] = sum[o<<1] + sum[o << 1 | 1];
}
int qurry(int l,int r,int o)
{
if(A <= l && r <= B)
{
return sum[o];
}
int ans = 0;
int mid = (l + r) >> 1;
if(mid >= A) ans += qurry(lson);
if(mid < B) ans += qurry(rson);
return ans;
}
//更新的时候记得用vis取得线段树下标,不要用原来树中的编号。
//当两个点的不在同一条重链上的时候重链的顶端节点要取,当在同一条重链上的时候重链的顶端节点不能取,要
//取顶端节点的son节点,因为顶端节点取了相当于多取了一条边
void solve(int a,int b,int c)
{
int q,w;
if(c == 0)
{
A = vis[edge[a][0]];
B = b;
update(1,n-1,1);
}
else
{
q = top[a],w = top[b];
int ans = 0;
while(q != w)
{
if(dep[q] < dep[w])
{
swap(q,w);
swap(a,b);
}
A = vis[q],B = vis[a];
a = fa[q];
q = top[a];
ans += qurry(1,n-1,1);
}
if(a != b)
{
if(dep[a] > dep[b])
swap(a,b);
A = vis[son[a]], B = vis[b];
ans += qurry(1,n-1,1);
}
printf("%d\n",ans);
}
}
int main()
{
while(scanf("%d %d",&n,&m) != EOF)
{
init();
int i,j;
for(i = 1; i < n; i++)
{
scanf("%d %d %d",&edge[i][0],&edge[i][1],&edge[i][2]);
add(edge[i][0],edge[i][1]);
add(edge[i][1],edge[i][0]);
}
dfs1(1,1,1);
dfs2(1,1);
for(i = 1; i < n; i++)
{
if(dep[edge[i][0]] < dep[edge[i][1]])
swap(edge[i][0],edge[i][1]);
A = vis[edge[i][0]],B = edge[i][2];
update(1,n-1,1);
}
while(m--)
{
int a1,b1,c1;
scanf("%d %d %d",&a1,&b1,&c1);
solve(b1,c1,a1);
}
}
return 0;
}