题解思路:这题暴力也能过,暴力和线段是也就差了300ms左右。那么我们讲线段树怎么做minv[o]表示从这个区间的左边界出发经过这个区间内的任意一点后到达1的最小距离,
当然当时从一颗子树的叶子节点跟另一颗子树的某几个头节点组成的区间是无效的不需要纠结。addv【o】保存的是o-(o>>1)之间向上父节点的几段距离。那么就有minv[o]=min(minv[lc]+addv[lc],minv[rc]+addv[rc]);lc,rc分别是o的左右孩子
代码:
#include<bits/stdc++.h>
#define lowbit(x) (x&-x)
#define MAXN 200020
using namespace std;
int n,q;
int first[MAXN],targ[MAXN],nxt[MAXN],dist[MAXN],dfv[MAXN],dfe[MAXN],tp[MAXN],port[MAXN],cntd=1,cnte=1;
void AddEdge(int u,int v,int c){targ[cnte]=v;dist[cnte]=c;nxt[cnte]=first[u];first[u]=cnte++;}
long long addv[MAXN<<2],minv[MAXN<<2];
void maintain(int o){
int lc=o<<1,rc=lc|1;
minv[o]=min(minv[lc]+addv[lc],minv[rc]+addv[rc]);
}
void Add(int o,int L,int R,const int &ql,const int &qr,const int &v)
{
if(ql<=L&&R<=qr) addv[o]+=v;
else{
int m=L+R>>1,lc=o<<1,rc=lc|1;
if(ql<=m)Add(lc,L,m,ql,qr,v);
if(m<qr)Add(rc,m+1,R,ql,qr,v);
maintain(o);
}
}
long long Query(int o,int L,int R,const int &ql,const int &qr,long long added=0){
added+=addv[o];
if(ql<=L&&R<=qr) return minv[o]+added;
else{
int m=L+R>>1,lc=o<<1,rc=lc|1;
long long ans=(1ll<<63ll)-1ll;
if(ql<=m)ans=Query(lc,L,m,ql,qr,added);
if(m<qr)ans=min(ans,Query(rc,m+1,R,ql,qr,added));
return ans;
}
}
void DFS(int x){
dfv[x]=cntd++;
for(int i=first[x];i;i=nxt[i])DFS(targ[i]);
dfe[x]=cntd-1;
}
int main(){
scanf("%d%d",&n,&q);
int a,b,c,o;
for(int i=1;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
AddEdge(a,b,c);
}
for(int i=1;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
tp[a]=c;
port[i]=a;
}
DFS(1);
for(int i=1;i<cnte;i++)Add(1,1,n,dfv[targ[i]],dfe[targ[i]],dist[i]);
for(int i=1;i<=n;i++)Add(1,1,n,dfv[i],dfv[i],tp[i]);
while(q--){
scanf("%d%d%d",&o,&a,&b);
if(o==1){
if(a>=n){
a-=n-1;
a=port[a];
Add(1,1,n,dfv[a],dfv[a],b-tp[a]);
tp[a]=b;
}
else{
Add(1,1,n,dfv[targ[a]],dfe[targ[a]],b-dist[a]);
dist[a]=b;
}
}
else{
long long deepa=Query(1,1,n,dfv[a],dfv[a])-tp[a],
Tp=Query(1,1,n,dfv[a],dfe[a])-deepa,
deepb=Query(1,1,n,dfv[b],dfv[b])-tp[b];
if(dfv[b]>=dfv[a]&&dfe[b]<=dfe[a]) printf("%I64d\n",deepb-deepa);
else printf("%I64d\n",deepb+Tp);
}
}
}