FZU - 2082

有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 3
1 2 1
1 1 2
0 1 2
1 2 1
Sample Output
1

2

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 10005
typedef long long ll;
int g[maxn];
struct node{
	int to,nxt,vl;
}ed[maxn<<1];
int head[maxn],cnt;
void addedge(int u,int v,int vl){
	ed[cnt].to=v;
	ed[cnt].vl=vl;
	ed[cnt].nxt=head[u];
	head[u]=cnt++;
}

int sz[maxn],top[maxn],son[maxn],fa[maxn],p[maxn],dep[maxn];
int pos;
void dfs1(int u,int f,int d){
	dep[u]=d;	
	sz[u]=1;
	fa[u]=f;
	for(int i=head[u];~i;i=ed[i].nxt){
		int v=ed[i].to;
		if(v==f)continue;
		dfs1(v,u,d+1);
		sz[u]+=sz[v];
		if(son[u]==-1||sz[son[u]]<sz[v])son[u]=v;
	}
}
void dfs2(int u,int tp){
	top[u]=tp;
	p[u]=pos++;
	if(son[u]==-1)return;
	dfs2(son[u],tp);
	for(int i=head[u];~i;i=ed[i].nxt){
		int v=ed[i].to;
		if(v!=son[u]&&v!=fa[u]){
			dfs2(v,v);
		}
	}
}

struct T{
	int l,r;
	ll sum;
}stu[maxn*4];
void pushup(int rt){
	if(stu[rt].l==stu[rt].r)return ;
	stu[rt].sum=stu[rt<<1].sum+stu[(rt<<1)+1].sum;
	return ;
}
void build(int l,int r,int rt){
	stu[rt].l=l,stu[rt].r=r;
	if(l==r){
		stu[rt].sum=g[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,rt<<1);
	build(mid+1,r,(rt<<1)+1);
	pushup(rt);
	return ;
}
void updata(int a,int b,int r){
	if(stu[r].l==stu[r].r)
	{stu[r].sum=b,g[a]=b;
	return ;}
	int mid=(stu[r].l+stu[r].r)>>1;
	if(a>mid)updata(a,b,(r<<1)+1);
	else updata(a,b,r<<1);
	pushup(r);
	return ;
}
ll q(int l,int r,int rt){
	if(stu[rt].l==l&&stu[rt].r==r)return stu[rt].sum;
	int mid=(stu[rt].l+stu[rt].r)>>1;
	if(mid>=r)return q(l,r,rt<<1);
	else if(mid<l)return q(l,r,(rt<<1)+1);
	else return q(l,mid,rt<<1)+q(mid+1,r,(rt<<1)+1);
}
ll getsum(int u,int v){
	int f1=top[u],f2=top[v];
	ll ans=0;
	while(f1!=f2){
		if(dep[f1]<dep[f2]){
			swap(f1,f2);
			swap(u,v);
		}
		ans+=q(p[f1],p[u],1);
		u=fa[f1];
		f1=top[u];
	}
	if(u==v)return ans;
	if(dep[u]<dep[v])swap(u,v);
	ans+=q(p[son[v]],p[u],1);
	return ans;
}
int uu[maxn];
void init(){
	memset(head,-1,sizeof(head));
	cnt=0;
	memset(son,-1,sizeof(son));
	pos=0;
}
int main(){
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF){
		init();
		for(int i=1;i<n;i++){
			int u,v,vl;
			scanf("%d%d%d",&u,&v,&vl);
			addedge(u,v,vl);
			addedge(v,u,vl);
		}
		dfs1(1,0,0);
		dfs2(1,1);
		for(int i=0;i<cnt;i+=2){
			int v=ed[i].to,vl=ed[i].vl;
			int u=ed[i^1].to;
			if(dep[u]<dep[v])swap(u,v);
			g[p[u]]=vl;
			uu[i/2+1]=u;
		}
		build(0,n-1,1);
		while(m--){
			int a,b,f;
			scanf("%d%d%d",&f,&a,&b);
			if(f==0){
				updata(p[uu[a]],b,1);
			}
			else printf("%d\n",getsum(a,b));
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值