边权转化为点权的操作
把边权放在深度更大的点上
查询时候不查询公共祖先
接下来就是线段树单点,区间max
// Problem: P4114 Qtree1
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4114
// Memory Limit: 500 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<vector>
using namespace std;
const int N=1e5+9;
int n;
int a[N];
//树剖
//1.转成线性部分
struct edge{
int u,v,w;
}ee[N];
vector<edge> e[N];
void add(int u,int v,int w){//记录边
e[u].push_back({v,u,w});
e[v].push_back({u,v,w});
}
int fa[N],dep[N],sz[N],wc[N],dis[N];
void dfs1(int u,int f){//fa dep sz wc
fa[u]=f;
sz[u]=1;
dep[u]=dep[f]+1;
for(auto & [x,y,z] : e[u]){
if(x==f){
dis[u]=z;//边权给儿子
continue;
}
if(x!=f){
dfs1(x,u);
sz[u]+=sz[x];
if(sz[x]>sz[wc[u]]){
wc[u]=x;
}
}
}
}
int dfn[N],rdfn[N],top[N],vistime;
void dfs2(int u,int Top){//dfn rdfn top
dfn[u]=++vistime;
a[vistime]=dis[u];
top[u]=Top;
if(wc[u]){
dfs2(wc[u],Top);
for(auto & [x,y,z] : e[u]){
if(x!=wc[u] && x!=fa[u]){
dfs2(x,x);
}
}
}
}
//2.线段树维护
struct SEG{
#define INF (1<<31)
#define ll long long
#define tl(id) (id<<1)
#define tr(id) (id<<1|1)
#define li inline
struct node{
int mx;
}seg[N<<2];
#define pushup(id) seg[id].mx=max(seg[tl(id)].mx,seg[tr(id)].mx)
li int inrange(int L,int R,int l,int r){return l<=L && R<=r;}
li int outofrange(int L,int R,int l,int r){return L>r || R<l;}
li void build(const int id,int l,int r){
if(l==r){
seg[id].mx=a[l];
return;
}
int mid=(l+r)>>1;
build(tl(id),l,mid);
build(tr(id),mid+1,r);
pushup(id);
}
li ll query(int id,int L,int R,int l,int r){
if(inrange(L,R,l,r)){
return seg[id].mx;
}else if(!outofrange(L,R,l,r)){
int mid=(L+R)>>1;
return max(query(tl(id),L,mid,l,r),query(tr(id),mid+1,R,l,r));
}else{
return 0;
}
}
li void update(int id,int l,int r,int pos,int v){
if(l==r){
seg[id].mx=v;
return;
}
int mid=(l+r)>>1;
if(mid>=pos){
update(tl(id),l,mid,pos,v);
}else{
update(tr(id),mid+1,r,pos,v);
}
pushup(id);
}
}tr;
//3.找LCA,同时完成操作
ll ask(int u,int v){
if(u==v){
return 0;
}
ll res=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]){
swap(u,v);
}
res=max(res,tr.query(1,1,n,dfn[top[u]],dfn[u]));
u=fa[top[u]];
}
if(dfn[u]>dfn[v]){
swap(u,v);
}
res=max(res,tr.query(1,1,n,dfn[u]+1,dfn[v]));//去掉公共祖先
return res;
}
int main(){
cin>>n;
for(int i=1;i<=n-1;i++){
int u,v,w;
cin>>u>>v>>w;
ee[i]={u,v,w};
add(u,v,w);
}
dfs1(1,0);
dfs2(1,1);
tr.build(1,1,n);
string op;
while(cin>>op){
if(op=="CHANGE"){
int i,t;
cin>>i>>t;
if(dep[ee[i].u]>dep[ee[i].v]){//放在深度更大的点
i=ee[i].u;
}else{
i=ee[i].v;
}
tr.update(1,1,n,dfn[i],t);
}else if(op=="QUERY"){
int a,b;
cin>>a>>b;
cout<<ask(a,b)<<'\n';
}else{
break;
}
}
return 0;
}