fzu 2082 过路费(树链剖分)

思路:树链剖分的裸题了


#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn = 50000+100;
int siz[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],id[maxn];
int tot;
int val[maxn];
vector<int>e[maxn];
int n,m;
struct Node
{
	int u,v;
    LL val;
}nodes[maxn];
LL sum[maxn<<2];
#define lson i*2,l,m
#define rson i*2+1,m+1,r
void push_up(int i)
{
	sum[i] = sum[i*2] + sum[i*2+1];
}
void build(int i,int l,int r)
{
	if(l==r)
	{
		sum[i]=val[l];
		return;
	}
	int m = (l+r)>>1;
	build(lson);
	build(rson);
	push_up(i);
}
LL query(int ql,int qr,int i,int l,int r)
{
	if(ql <= l && qr>=r)
	    return sum[i];
	int m = (l+r)>>1;
	LL ans = 0;
	if (ql <= m)
		ans+=query(ql,qr,lson);
	if (m<qr)
		ans+=query(ql,qr,rson);
	return ans;
}

void update(int id,int val,int i,int l,int r)
{
	if(l==r)
	{
		sum[i]=val;
		return;
	}
	int m = (l+r)>>1;
	if(id <=m)
		update(id,val,lson);
	else
		update(id,val,rson);
	push_up(i);
}

void dfs1(int u,int f,int d)
{
	siz[u]=1;
	son[u]=0;
	fa[u]=f;
	dep[u]=d;
	for(int i = 0;i<e[u].size();i++)
	{
		int v = e[u][i];
		if(v==f)
			continue;
		dfs1(v,u,d+1);
		siz[u]+=siz[v];
		if(siz[son[u]] < siz[v])
			son[u]=v;
	}
}
void dfs2(int u,int tp)
{
	top[u]=tp;
	id[u]=++tot;
	if(son[u])
		dfs2(son[u],tp);
	for(int i = 0;i<e[u].size();i++)
	{
		int v= e[u][i];
		if(v==fa[u] || v == son[u])
			continue;
		dfs2(v,v);
	}
}

LL Yougth(int u,int v)
{
	int tp1 = top[u],tp2 = top[v];
	LL ans = 0;
	while(tp1!=tp2)
	{
		if (dep[tp1] < dep[tp2])
		{
			swap(tp1,tp2);
			swap(u,v);
		}
		ans +=query(id[tp1],id[u],1,1,tot);
		u = fa[tp1];
		tp1 = top[u];
	}
	if(u==v)
		return ans;
	if(dep[u] > dep[v])
		swap(u,v);
	ans += query(id[son[u]],id[v],1,1,tot);
	return ans;
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(int i = 0;i<=n;i++)
			e[i].clear();
		for(int i = 1;i<n;i++)
		{
			scanf("%d%d%lld",&nodes[i].u,&nodes[i].v,&nodes[i].val);
			e[nodes[i].u].push_back(nodes[i].v);
			e[nodes[i].v].push_back(nodes[i].u);
		}
		tot = 0;
		dfs1(1,0,1);
		dfs2(1,1);
        for(int i = 1;i<n;i++)
		{
			if (dep[nodes[i].u] < dep[nodes[i].v])
				swap(nodes[i].u,nodes[i].v);
			val[id[nodes[i].u]] = nodes[i].val;
		}
		build(1,1,tot);
		while(m--)
		{
			int op;
			scanf("%d",&op);
			if(op==1)
			{
				int uu,vv;
				scanf("%d%d",&uu,&vv);
                printf("%lld\n",Yougth(uu,vv));
			}
			else 
			{
				int uu;
				LL v;
				scanf("%d%lld",&uu,&v);
                update(id[nodes[uu].u],v,1,1,tot);
			}
		}
	}
}



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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值