F

//#include<bits/stdc++.h>
//#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<iostream>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
using namespace std;
#define ll long long
#define pb push_back
const int maxn=1e6+7;
const int inf=0x3f3f3f3f;

struct EDGE{
	int u,v,val,next;
}G[maxn<<1];
int tot;int head[maxn];
void init(){
	memset(head,-1,sizeof head);tot=0;
}
void addedge(int u,int v,int w){
	tot++;G[tot]={u,v,w,head[u]};head[u]=tot;
}

int vs[maxn<<1];
int in[maxn],out[maxn];
int tim; 
int dep[maxn<<1];
int id[maxn];
int pre[maxn];
void dfs(int u,int fa,int d){
	pre[u]=fa;
	id[u]=++tim;vs[tim]=u;dep[tim]=d;
	in[u]=tim;out[u]=tim;
	for(int i=head[u];~i;i=G[i].next){
		EDGE e=G[i];
		if(e.v==fa)continue;
		dfs(e.v,u,d+e.val);
		vs[++tim]=u;dep[tim]=d;out[u]=tim;
	}
}

struct node{
	int fa;		//区间内公共祖先
	int mindep;
	int add;	//lazy
}ST[maxn<<2];
void pushdown(int rt){
	if(ST[rt].add){
		ST[rt<<1].mindep+=ST[rt].add;ST[rt<<1|1].mindep+=ST[rt].add;
		ST[rt<<1].add+=ST[rt].add;ST[rt<<1|1].add+=ST[rt].add;
		ST[rt].add=0;
	}
}
void pushup(int rt){
	if(ST[rt<<1].mindep<=ST[rt<<1|1].mindep){
		ST[rt].mindep=ST[rt<<1].mindep;
		ST[rt].fa=ST[rt<<1].fa;
	}else{
		ST[rt].mindep=ST[rt<<1|1].mindep;
		ST[rt].fa=ST[rt<<1|1].fa;
	}
}
void build(int l,int r,int rt){
	if(l==r){
		ST[rt].mindep=dep[l];
		ST[rt].fa=vs[l];
		ST[rt].add=0;
		return;
	}
	ST[rt].add=0;
	int m=l+r>>1;
	build(l,m,rt<<1);
	build(m+1,r,rt<<1|1);
	pushup(rt);
}
void update(int a,int b,int c,int l,int r,int rt){
	if(a<=l&&b>=r){
		ST[rt].mindep+=c;
		ST[rt].add+=c;
		return;
	}
	pushdown(rt);
	int m=l+r>>1;
	if(a<=m)update(a,b,c,l,m,rt<<1);
	if(b>m)update(a,b,c,m+1,r,rt<<1|1);
	pushup(rt);
}
node query(int a,int b,int l,int r,int rt){	//查询a-b内的祖先
	//cout<<a<<" "<<b<<" "<<l<<" "<<r<<endl;
	if(a<=l&&b>=r){
		return ST[rt];
	}
	pushdown(rt);
	int m=l+r>>1;
	node n2={0,inf,0},n1={0,inf,0};
	if(a<=m)n1=query(a,b,l,m,rt<<1);
	if(b> m)n2=query(a,b,m+1,r,rt<<1|1);
	if(n1.mindep<n2.mindep){return n1;}
	else return n2;
}

int main(){
	int n,q,s;
	while(~scanf("%d%d%d",&n,&q,&s)){
		init();
		for(int i=1;i<n;i++){
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			//if(u>v)swap(u,v);
			addedge(u,v,w);
			addedge(v,u,w);
		}

		int now=s;
		tim=0;
		dep[s]=0;	
		dfs(s,s,0);
		
		build(1,tim,1);
	
		for(int i=1;i<=q;i++){
			int kind;int a,b;
			scanf("%d",&kind);
			if(kind){			//改边
				scanf("%d%d",&a,&b);
				a=2*a-1;
				int flag=0;
				if(pre[G[a].v]==G[a].u){flag=1;}
				else a++;
				
				EDGE e=G[a];

				int plus=b-e.val;

				update(in[e.v],out[e.v],plus,1,tim,1);
				if(flag){
					G[a].val=b;
					G[a+1].val=b;
				}else{
					G[a].val=b;
					G[a-1].val=b;
				}
				//for(int i=1;i<=tim;i++){
				//	cout<<vs[i]<<"ss"<<endl;
				//}
				
			}else{
				scanf("%d",&a);
				//cout<<now<<" "<<a<<endl;
				
				node anc=
					query(min(id[a],id[now]),max(id[now],id[a]),1,tim,1);

				node n1,n2;
				n1=query(id[now],id[now],1,tim,1);
				n2=query(id[a],id[a],1,tim,1);

				int ans=n1.mindep+n2.mindep-anc.mindep*2;
				//cout<<n1.mindep<<" "<<n2.mindep<<" "<<anc.mindep<<endl;
				//cout<<n1.fa<<" "<<n2.fa<<" "<<anc.fa<<endl;
				printf("%d
",ans);
				now=a;
			}
		}
	}
}

/*
 3 100 2
 1 2 6
 1 3 5
 1 1 4
 0 1
 */

核心就是vs序列存下的in[u],out[u]的中间段只有u的子树

做法肯定不是最优的,因为检查每个节点的深度我都用到了线段树查询,慢了3倍

换上树状数组肯定能更快,但我懒得学。。

双向边的编号修改难死我了。。。还好想出办法解决了

(其实是别人的代码我看不懂

原文地址:https://www.cnblogs.com/Drenight/p/8611301.html