Description

给出一个树,每条边有边权,支持两种操作,询问 \(u,v\) 路径上边权最大值,修改第 \(i\) 条边的边权,\(n\leqslant 10^4,T\leqslant 10\)

Sol

树链剖分.

基于边的树链剖分,对于一个点,可能有许多儿子,但是它只能有一个父亲,给它编号表示它到它父亲的边,只需要修改查询的是最后一步就可以了.

Code

#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;

#define debug(a) cout<<#a<<"="<<a<<" "
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc (o<<1|1)
const int N = 10005;

inline int in(int x=0,char ch=getchar()){ while(ch>'9'||ch<'0') ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x; }

int n,e,cnt;
struct Edge{ int fr,to,v; }edge[N];
vector<Edge> g[N];
int f[N],cost[N],dep[N],son[N],top[N],sz[N],p[N];
int d[N<<2];

void Add_Edge(int fr,int to,int v){
	edge[++e]=(Edge){ fr,to,v };
	g[fr].push_back((Edge){ fr,to,v });
	g[to].push_back((Edge){ to,fr,v });
}
void DFS1(int u,int fa){
	sz[u]=1,son[u]=0,dep[u]=dep[fa]+1,f[u]=fa;
	for(int i=0,lim=g[u].size(),v;i<lim;i++) if((v=g[u][i].to)!=fa){
		DFS1(v,u),sz[u]++;
		if(!son[u]||sz[son[u]]<sz[v]) son[u]=v;
	}
}
void DFS2(int u,int tp){
	p[u]=++cnt,top[u]=tp;
	if(son[u]) DFS2(son[u],tp);
	for(int i=0,lim=g[u].size(),v;i<lim;i++) if((v=g[u][i].to)!=f[u]&&v!=son[u])
		DFS2(v,v);
}
void Build(int o,int l,int r){
	if(l==r){ d[o]=cost[l];return; }
	Build(lc,l,mid),Build(rc,mid+1,r);
	d[o]=max(d[lc],d[rc]);
}
void Change(int o,int l,int r,int x,int v){
	if(l==r){ d[o]=v;return; }
	if(x<=mid) Change(lc,l,mid,x,v);
	else Change(rc,mid+1,r,x,v);
	d[o]=max(d[lc],d[rc]);
}
int QueryMax(int o,int l,int r,int L,int R){
	if(L<=l&&r<=R) return d[o];int res=0;
	if(L<=mid) res=max(res,QueryMax(lc,l,mid,L,R));
	if(R>mid) res=max(res,QueryMax(rc,mid+1,r,L,R));
	return res;
}
int GetAns(int u,int v){
	int res=0,f1=top[u],f2=top[v];
	while(f1!=f2){
		if(dep[f1]<dep[f2]) swap(u,v),swap(f1,f2);
		res=max(res,QueryMax(1,1,n,p[f1],p[u]));
		u=f[f1],f1=top[u];
	}
	if(dep[u]>dep[v]) swap(u,v);
	if(dep[v]==dep[u]) return res;
	else return max(res,QueryMax(1,1,n,p[u]+1,p[v]));
}
void clr(){ for(int i=0;i<N;i++) g[i].clear();cnt=0,e=0; }

int main(){
//	freopen("in.in","r",stdin);
//	freopen("out.out","w",stdout);
	ios::sync_with_stdio(false);
	for(int T=in();T--;){
		clr();
		n=in();
		for(int i=1,a,b,c;i<n;i++) a=in(),b=in(),c=in(),Add_Edge(a,b,c);
		DFS1(1,1),DFS2(1,1);
		
		for(int i=1;i<n;i++){
			int a=edge[i].fr,b=edge[i].to;
			if(dep[a]>dep[b]) swap(a,b),swap(edge[i].fr,edge[i].to);
			cost[p[b]]=edge[i].v;
		}
		
		Build(1,1,n);
		for(char opt[10];;){
			scanf("%s",opt);
			if(opt[0]=='D') break;
			int a=in(),b=in();
			if(opt[0]=='C') Change(1,1,n,p[edge[a].to],b);
			else printf("%d\n",GetAns(a,b));
//			debug(QueryMax(1,1,n,1,1)),debug(QueryMax(1,1,n,2,2)),debug(QueryMax(1,1,n,3,3))<<endl;
		}
	}return 0;
}