树链剖分记牢模板(含边 权)+例题
这是对点权计算的板子
#include<bits/stdc++.h> using namespace std; #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r #define pb push_back typedef long long ll; inline int read(){ int sum=0,x=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') x=0; ch=getchar(); } while(ch>='0'&&ch<='9') sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar(); return x?sum:-sum; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } const int M=1e5+5; int fa[M],son[M],top[M],dfn[M],deep[M],to[M],sz[M],cnt; ll a[M],tree[M<<2],lazy[M<<2]; vector<int>g[M]; void dfs1(int u, int o) { fa[u] = o; sz[u] = 1; deep[u] = deep[o] + 1; for (int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if(v != o) { dfs1(v, u); sz[u] += sz[v]; if(sz[v] > sz[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { top[u] = t; dfn[u] = ++cnt; to[cnt] = u; if(!son[u]) return ; dfs2(son[u], t); for (int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if(v != fa[u] && v != son[u]) dfs2(v, v); } } int mod,n,m,reroot; void up(int root){ tree[root]=tree[root<<1]+tree[root<<1|1]; tree[root]%=mod; } void build(int root,int l,int r){ if(l==r){ tree[root]=a[to[l]]; return ; } int midd=(l+r)>>1; build(lson); build(rson); up(root); } void pushdown(int root,int len){ tree[root<<1]=(tree[root<<1]+lazy[root]*(len-(len>>1)))%mod; lazy[root<<1]=(lazy[root<<1]+lazy[root])%mod; tree[root<<1|1]=(tree[root<<1|1]+lazy[root]*(len>>1))%mod; lazy[root<<1|1]=(lazy[root<<1|1]+lazy[root])%mod; lazy[root]=0; } void update(int L,int R,ll w,int root,int l,int r){ if(L<=l&&r<=R){ tree[root]+=w*(r-l+1); tree[root]%=mod; lazy[root]+=w; lazy[root]%=mod; return ; } if(lazy[root]) pushdown(root,r-l+1); int midd=(l+r)>>1; if(L<=midd) update(L,R,w,lson); if(R>midd) update(L,R,w,rson); up(root); return ; } void updates(int u,int v,int w){ while(top[u]!=top[v]){ if(deep[top[u]]<deep[top[v]]) swap(u,v); update(dfn[top[u]],dfn[u],w,1,1,n); u=fa[top[u]]; } if(deep[u]<deep[v]) swap(u,v); update(dfn[v],dfn[u],w,1,1,n); } ll query(int L,int R,int root,int l,int r){ if(L<=l&&r<=R){ return tree[root]; } if(lazy[root]) pushdown(root,r-l+1); int midd=(l+r)>>1; ll ans=0; if(L<=midd) ans+=query(L,R,lson),ans%=mod; if(R>midd) ans+=query(L,R,rson),ans%=mod; return ans; } ll sum(int u,int v){ ll ans=0; while(top[u]!=top[v]){ if(deep[top[u]]<deep[top[v]]) swap(u,v); ans+=query(dfn[top[u]],dfn[u],1,1,n); u=fa[top[u]]; } if(deep[u]<deep[v]) swap(u,v); ans+=query(dfn[v],dfn[u],1,1,n); return ans; } int main(){ scanf("%d%d%d%d",&n,&m,&reroot,&mod); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); g[u].pb(v); g[v].pb(u); } dfs1(reroot,reroot); dfs2(reroot,reroot); // cout<<"!!"<<endl; build(1,1,n); while(m--){ int op; scanf("%d",&op); if(op==1){ int x,y; ll z; scanf("%d%d%lld",&x,&y,&z); updates(x,y,z); } else if(op==2){ int x,y; scanf("%d%d",&x,&y); printf("%lld\n",sum(x,y)); } else if(op==3){ int x; ll y; scanf("%d%lld",&x,&y); update(dfn[x],dfn[x]+sz[x]-1,y,1,1,n); //cout<<dfn[x]<<"!!"<<sz[x]; } else{ int x; scanf("%d",&x); printf("%lld\n",query(dfn[x],dfn[x]+sz[x]-1,1,1,n)); } }return 0; }
下面是对于计算边权的板子的例题:(题目大意是:对于P :u,v表示u到v之间的边+1。对于Q:u,v表示输出u到v之间边之和;)
千万注意俩者在add和solve函数部分的区别!!!!!!!!!!!!!!!
https://vjudge.net/problem/SPOJ-GRASSPLA
#include<iostream> #include<cstring> #include<vector> #include<algorithm> #include<vector> using namespace std; typedef long long ll; const int M=1e5+5; vector<int>g[M]; int fa[M],son[M],sz[M],dfn[M],top[M],deep[M]; ll tree[M<<2],lazy[M<<2]; int cnt,n; void dfs1(int u,int from){ fa[u]=from; sz[u]=1; deep[u]=deep[from]+1; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(v!=from){ dfs1(v,u); sz[u]+=sz[v]; if(sz[v]>sz[son[u]]) son[u]=v; } } } void dfs2(int u,int t){ top[u]=t; dfn[u]=++cnt; if(!son[u]) return; dfs2(son[u],t); for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } } void pushdown(int root,int len){ int sign=lazy[root]; lazy[root<<1]+=sign; lazy[root<<1|1]+=sign; tree[root<<1]+=(len-(len>>1))*1ll*sign; tree[root<<1|1]+=(len>>1)*1ll*sign; lazy[root]=0; } void update(int L,int R,int x,int root,int l,int r){ if(L<=l&&r<=R){ tree[root]+=x*(r-l+1)*1ll; lazy[root]+=x; return ; } if(lazy[root]) pushdown(root,r-l+1); int midd=(l+r)>>1; if(L<=midd) update(L,R,x,root<<1,l,midd); if(R>midd) update(L,R,x,root<<1|1,midd+1,r); tree[root]=tree[root<<1]+tree[root<<1|1]; } void add(int v,int u,int x){ while(top[u]!=top[v]){ if(deep[top[u]]<deep[top[v]]) swap(u,v); update(dfn[top[u]],dfn[u],w,1,1,n); u=fa[top[u]]; } if(deep[u]<deep[v]) swap(u,v); update(dfn[v]+1,dfn[u],w,1,1,n); } ll query(int L,int R,int root,int l,int r){ if(L<=l&&r<=R) return tree[root]; ll ans=0; int midd=l+r>>1; if(lazy[root]) pushdown(root,r-l+1); if(L<=midd) ans+=query(L,R,root<<1,l,midd); if(R>midd) ans+=query(L,R,root<<1|1,midd+1,r); tree[root]=tree[root<<1]+tree[root<<1|1]; return ans; } ll solve(int v,int u){ ll ans=0; while(top[u]!=top[v]){ if(deep[top[u]]<deep[top[v]]) swap(u,v); ans+=query(dfn[top[u]],dfn[u],1,1,n); u=fa[top[u]]; } if(deep[u]<deep[v]) swap(u,v); ans+=query(dfn[v]+1,dfn[u],1,1,n); return ans; } int main(){ int m; scanf("%d%d",&n,&m); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); g[x].push_back(y); g[y].push_back(x); } dfs1(1,1); dfs2(1,1); /*for(int i=1;i<=n;i++) cout<<dfn[i]<<"~"; cout<<endl;*/ while(m--){ char s[2]; int x,y; scanf("%s%d%d",s,&x,&y); if(s[0]=='P') add(x,y,1); else printf("%lld\n",solve(x,y));// } return 0; }
加换根操作的题
描述
给定一棵 n 个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值。下面依次进行 m 个操作,操作分为如下五种类型:
换根:将一个指定的节点设置为树的新根。
修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值。
修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值。
询问路径:询问某条路径上节点的权值和。
询问子树:询问某个子树内节点的权值和。
输入
第一行为一个整数 n,表示节点的个数。
第二行 n 个整数表示第i个节点的初始权值 ai
第三行 n−1 个整数,表示i+1 号节点的父节点编号 fi+1 (1⩽fi+1⩽n)
第四行一个整数 m,表示操作个数。
接下来 m 行,每行第一个整数表示操作类型编号:(1⩽u,v⩽n)
若类型为 1,则接下来一个整数 u,表示新根的编号。
若类型为 2,则接下来三个整数 u,v,k,分别表示路径两端的节点编号以及增加的权值。
若类型为3,则接下来两个整数 u,k,分别表示子树根节点编号以及增加的权值。
若类型为 4,则接下来两个整数u,v,表示路径两端的节点编号。
若类型为 5,则接下来一个整数 u,表示子树根节点编号。
输出
对于每一个类型为 4 或 5 的操作,输出一行一个整数表示答案。
样例输入
6
1 2 3 4 5 6
1 2 1 4 4
6
4 5 6
2 2 4 1
5 1
1 4
3 1 2
4 2 5
样例输出
15
24
19
换根:对于路径查询、路径修改无影响,但对子树的从属,查询之类的有影响
考虑root为当前的根,u为所求子树的根,lca为原图中的lca
1.u==root,那么u 的子树就是整棵树。
2.LCA(root,u)≠u,即root不在u的子树中。那么u现在的子树就是原来的子树
3.LCA(root,u)=u,即u 在原来的树中是root 的祖先。那么我们找到u 到root 路径上的第一个儿子。这个儿子对应的原树中的子树,就是现在u 的子树的补集。
#include<bits/stdc++.h> using namespace std; #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r #define pb push_back typedef long long ll; const int M=1e5+5; ll tree[M<<2],lazy[M<<2],a[M]; int dfn[M],sz[M],fa[M],son[M],deep[M],top[M],cnt,to[M]; vector<int>g[M]; inline int read(){ int sum=0,x=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') x=0; ch=getchar(); } while(ch>='0'&&ch<='9') sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar(); return x?sum:-sum; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } void dfs1(int u, int o) { fa[u] = o; sz[u] = 1; deep[u] = deep[o] + 1; for (int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if(v != o) { dfs1(v, u); sz[u] += sz[v]; if(sz[v] > sz[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { top[u] = t; dfn[u] = ++cnt; to[cnt] = u; if(!son[u]) return ; dfs2(son[u], t); for (int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if(v != fa[u] && v != son[u]) dfs2(v, v); } } int n,reroot=1; void up(int root){ tree[root]=tree[root<<1]+tree[root<<1|1]; tree[root]; } void build(int root,int l,int r){ if(l==r){ tree[root]=a[to[l]]; return ; } int midd=(l+r)>>1; build(lson); build(rson); up(root); } void pushdown(int root,int len){ tree[root<<1]=(tree[root<<1]+lazy[root]*(len-(len>>1))); lazy[root<<1]=(lazy[root<<1]+lazy[root]); tree[root<<1|1]=(tree[root<<1|1]+lazy[root]*(len>>1)); lazy[root<<1|1]=(lazy[root<<1|1]+lazy[root]); lazy[root]=0; } void update(int L,int R,ll w,int root,int l,int r){ if(L<=l&&r<=R){ tree[root]+=w*(r-l+1); lazy[root]+=w; return ; } if(lazy[root]) pushdown(root,r-l+1); int midd=(l+r)>>1; if(L<=midd) update(L,R,w,lson); if(R>midd) update(L,R,w,rson); up(root); return ; } void Update(int u,int v,int w){ while(top[u]!=top[v]){ if(deep[top[u]]<deep[top[v]]) swap(u,v); update(dfn[top[u]],dfn[u],w,1,1,n); u=fa[top[u]]; } if(deep[u]<deep[v]) swap(u,v); update(dfn[v],dfn[u],w,1,1,n); } ll query(int L,int R,int root,int l,int r){ if(L<=l&&r<=R){ return tree[root]; } if(lazy[root]) pushdown(root,r-l+1); int midd=(l+r)>>1; ll ans=0; if(L<=midd) ans+=query(L,R,lson); if(R>midd) ans+=query(L,R,rson); return ans; } ll sum(int u,int v){ ll ans=0; while(top[u]!=top[v]){ if(deep[top[u]]<deep[top[v]]) swap(u,v); ans+=query(dfn[top[u]],dfn[u],1,1,n); u=fa[top[u]]; } if(deep[u]<deep[v]) swap(u,v); ans+=query(dfn[v],dfn[u],1,1,n); return ans; } int find(int x,int y){ //找x到y的第一个儿子 while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]]) swap(x,y); if(fa[top[x]]==y) return top[x]; x=fa[top[x]]; } if(deep[x]<deep[y]) swap(x,y); return son[y]; } int LCA(int u,int v){ while(top[u]!=top[v]){ if(deep[top[u]]<deep[top[v]]) swap(u,v); u=fa[top[u]]; } return deep[u]>deep[v]?v:u; } void Updatesub(int u,ll w){//操作3用到 if(u==reroot){ update(1,n,w,1,1,n); return ; } int nearlca=LCA(u,reroot); if(nearlca!=u){ update(dfn[u],dfn[u]+sz[u]-1,w,1,1,n); return ; } else{ int nearchild=find(u,reroot); update(1,n,w,1,1,n); update(dfn[nearchild],dfn[nearchild]+sz[nearchild]-1,-w,1,1,n); return ; } } ll sumsub(int x){//操作5 if(x==reroot) return query(1,n,1,1,n); int nearlca=LCA(x,reroot); if(nearlca!=x) return query(dfn[x],dfn[x]+sz[x]-1,1,1,n); int nearch=find(x,reroot); ll ans=query(1,n,1,1,n); return ans-query(dfn[nearch],dfn[nearch]+sz[nearch]-1,1,1,n); } int main(){ n=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=2;i<=n;i++){ int x; scanf("%d",&x); g[x].pb(i); g[i].pb(x); } dfs1(1,1); dfs2(1,1); build(1,1,n); int m; m=read(); while(m--){ int op=read(); if(op==1){ int x=read(); reroot=x; } else if(op==2){ int u=read(),v=read(); ll w=1ll*read(); Update(u,v,w); } else if(op==3){ int u=read(); ll w=1ll*read(); Updatesub(u,w); } else if(op==4){ int u=read(),v=read(); printf("%lld\n",sum(u,v)); } else{ int u=read(); printf("%lld\n",sumsub(u)); } } return 0; } 更新查找链换码风
题:https://codeforces.com/contest/343/problem/D
#include<bits/stdc++.h> using namespace std; #define pb push_back #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r const int M=5e5+5; int sz[M],deep[M],fa[M],dfn[M],top[M],son[M],tree[M<<2],lazy[M<<2],cnt,n; vector<int>g[M]; void dfs1(int u,int f){ sz[u]=1; deep[u]=deep[f]+1; fa[u]=f; for(auto v: g[u]){ if(v!=f){ dfs1(v,u); sz[u]+=sz[v]; if(sz[v]>sz[son[u]]) son[u]=v; } } } void dfs2(int u,int t){ top[u]=t; dfn[u]=++cnt; /// to[cnt]=u; if(!son[u]) return ; dfs2(son[u],t); for(auto v:g[u]){ if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } } void pushdown(int root){ tree[root<<1]=tree[root<<1|1]=lazy[root]; lazy[root<<1]=lazy[root<<1|1]=lazy[root]; lazy[root]=-1; } void update(int L,int R,int w,int root,int l,int r){ if(L<=l&&r<=R){ tree[root]=w; lazy[root]=w; return ; } if(lazy[root]!=-1) pushdown(root); int midd=(l+r)>>1; if(L<=midd) update(L,R,w,lson); if(R>midd) update(L,R,w,rson); } int query(int pos,int root,int l,int r){ if(l==r){ return tree[root]; } if(lazy[root]!=-1) pushdown(root); int midd=(l+r)>>1; if(pos<=midd) return query(pos,lson); if(pos>midd) return query(pos,rson); } void add(int u,int v,int w){ while(top[u]!=top[v]){ if(deep[top[u]]<deep[top[v]]){ swap(u,v); } update(dfn[top[u]],dfn[u],w,1,1,n); u=fa[top[u]]; } if(deep[u]<deep[v]) swap(u,v); update(dfn[v],dfn[u],w,1,1,n); } int main(){ memset(lazy,-1,sizeof(lazy)); scanf("%d",&n); for(int u,v,i=1;i<n;i++){ scanf("%d %d",&u,&v); g[u].pb(v); g[v].pb(u); } dfs1(1,1); dfs2(1,1); int m; scanf("%d",&m); while(m--){ int op,x; scanf("%d%d",&op,&x); if(op==1){ update(dfn[x],dfn[x]+sz[x]-1,1,1,1,n); } else if(op==2){ add(1,x,0); } else{ printf("%d\n",query(dfn[x],1,1,n)); } } return 0; }
洛谷:https://www.luogu.org/problem/P2486
#include<bits/stdc++.h> using namespace std; const int M=3e5+5; struct node{ int l,r,cnt,lazy; node(int l1=0,int r1=0,int cnt1=0,int lazy1=0):l(l1),r(r1),cnt(cnt1),lazy(lazy1){} }tree[M<<2]; int fa[M],sz[M],deep[M],dfn[M],son[M],to[M],a[M],top[M],cnt,n; char s[2]; vector<int>g[M]; void dfs1(int u,int from){ fa[u]=from; sz[u]=1; deep[u]=deep[from]+1; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(v!=from){ dfs1(v,u); sz[u]+=sz[v]; if(sz[v]>sz[son[u]]) son[u]=v; } } } void dfs2(int u,int t){ top[u]=t; dfn[u]=++cnt; to[cnt]=u; if(!son[u]) return ; dfs2(son[u],t); for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } } void up(int root){ tree[root].cnt=tree[root<<1].cnt+tree[root<<1|1].cnt; if(tree[root<<1].r==tree[root<<1|1].l) tree[root].cnt--; tree[root].l=tree[root<<1].l; tree[root].r=tree[root<<1|1].r; } void build(int root,int l,int r){ tree[root].lazy=0; if(l==r){ tree[root].l=tree[root].r=a[to[l]]; tree[root].cnt=1; return ; } int midd=(l+r)>>1; build(root<<1,l,midd); build(root<<1|1,midd+1,r); up(root); } void pushdown(int root){ tree[root<<1]=tree[root<<1|1]=node(tree[root].l,tree[root].r,1,tree[root].lazy); tree[root].lazy=0; } void update(int L,int R,int x,int root,int l,int r){ if(L<=l&&r<=R){ tree[root]=node(x,x,1,x); return ; } if(tree[root].lazy) pushdown(root); int midd=(l+r)>>1; if(L<=midd) update(L,R,x,root<<1,l,midd); if(R>midd) update(L,R,x,root<<1|1,midd+1,r); up(root); } void add(int u,int v ,int w){ int fu=top[u],fv=top[v]; while(fu!=fv){ if(deep[fu]>=deep[fv]) update(dfn[fu],dfn[u],w,1,1,n),u=fa[fu],fu=top[u]; else update(dfn[fv],dfn[v],w,1,1,n),v=fa[fv],fv=top[v]; } if(dfn[u]<=dfn[v]) update(dfn[u],dfn[v],w,1,1,n); else update(dfn[v],dfn[u],w,1,1,n); } node meger(node a,node b){ if(!a.cnt) return b; if(!b.cnt) return a; node ans=node(0,0,0,0); ans.cnt=a.cnt+b.cnt; if(a.r==b.l) ans.cnt--; ans.l=a.l; ans.r=b.r; return ans; } node query(int L,int R,int root,int l,int r){ if(L<=l&&r<=R){ return tree[root]; } if(tree[root].lazy) pushdown(root); int midd=(l+r)>>1; node ans; if(L<=midd) ans=query(L,R,root<<1,l,midd); if(R>midd) ans=meger(ans,query(L,R,root<<1|1,midd+1,r)); up(root); return ans; } int solve(int u,int v){ node l,r; int fv=top[v],fu=top[u]; while(fv!=fu){ if(deep[fu]>=deep[fv]) l=meger(query(dfn[fu],dfn[u],1,1,n),l),u=fa[fu],fu=top[u]; else r=meger(query(dfn[fv],dfn[v],1,1,n),r),v=fa[fv],fv=top[v]; } if(dfn[u]<=dfn[v]) r=meger(query(dfn[u],dfn[v],1,1,n),r); else l=meger(query(dfn[v],dfn[u],1,1,n),l); swap(l.l,l.r); l=meger(l,r);//线段树是沿子树往下搜的,所以在合并的时候要保证同方向(因为这涉及到链的颜色排布问题,如果俩条链不同向可能会导致结果发生错误 return l.cnt; } int main(){ int m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); }//cout<<"!!"<<endl; dfs1(1,1); dfs2(1,1); build(1,1,n); while(m--){ int u,v,w; scanf("%s",s); if(s[0]=='Q'){ scanf("%d%d",&u,&v); printf("%d\n",solve(u,v)); } else{ scanf("%d%d%d",&u,&v,&w); add(u,v,w); } } return 0; }
题:https://www.luogu.org/problem/P4315
#include<bits/stdc++.h> using namespace std; const int MAXN=1e5+10; const int MAXM=2e5+10; int n,m,cnt=1; int head[MAXN],depth[MAXN],siz[MAXN],son[MAXN],fa[MAXN],top[MAXN]; int dfn[MAXN],ys[MAXN],tot; int a[MAXN]; struct Tree{ int l,r; int maxx,add; int cover; }tr[MAXN<<2]; struct Edge{ int nxt,to,w; }edge[MAXM]; int Read(){ int i=0,f=1; char c; for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar()); if(c=='-') f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar()) i=(i<<3)+(i<<1)+c-'0'; return i*f; } void add(int x,int y,int z){ cnt++; edge[cnt].nxt=head[x]; head[x]=cnt; edge[cnt].to=y; edge[cnt].w=z; } void dfs1(int u,int f){ siz[u]=1; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(v==f) continue; a[v]=edge[i].w; depth[v]=depth[u]+1,fa[v]=u; dfs1(v,u); siz[u]+=siz[v]; if(siz[v]>siz[son[u]]) son[u]=v; } } void dfs2(int u,int tp){ top[u]=tp; dfn[u]=++tot; ys[tot]=u; if(!son[u]) return ; dfs2(son[u],tp); for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(v==fa[u]||v==son[u]) continue; dfs2(v,v); } } void push_up(int root){ tr[root].maxx=max(tr[root<<1].maxx,tr[root<<1|1].maxx); } void push_cover(int root,int v){ tr[root].cover=v; tr[root].add=0; tr[root].maxx=v; } void push_add(int root,int v){ tr[root].add+=v; tr[root].maxx+=v; } void push_down(int root){ if(tr[root].cover!=-1){ push_cover(root<<1,tr[root].cover); push_cover(root<<1|1,tr[root].cover); tr[root].cover=-1; } if(tr[root].add){ push_add(root<<1,tr[root].add); push_add(root<<1|1,tr[root].add); tr[root].add=0; } } void build(int root,int l,int r){ tr[root].cover=-1; tr[root].l=l,tr[root].r=r; if(l==r){ tr[root].maxx=a[ys[l]]; return ; } int mid=l+r>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); push_up(root); } void update_cover(int root,int l,int r,int L,int R,int key){ if(l>R||r<L) return ; if(L<=l&&r<=R){ push_cover(root,key); return ; } push_down(root); int mid=(l+r)>>1; if(R<=mid) update_cover(root<<1,l,mid,L,R,key); else{ if(L>mid) update_cover(root<<1|1,mid+1,r,L,R,key); else update_cover(root<<1,l,mid,L,mid,key),update_cover(root<<1|1,mid+1,r,mid+1,R,key); } push_up(root); } void update_add(int root,int l,int r,int L,int R,int key){ if(l>R||r<L) return ; if(L<=l&&r<=R){ push_add(root,key); return ; } push_down(root); int mid=l+r>>1; if(R<=mid) update_add(root<<1,l,mid,L,R,key); else{ if(L>mid) update_add(root<<1|1,mid+1,r,L,R,key); else update_add(root<<1,l,mid,L,mid,key),update_add(root<<1|1,mid+1,r,mid+1,R,key); } push_up(root); } int query(int root,int l,int r,int L,int R){ if(l>R||r<L) return 0; if(L<=l&&r<=R) return tr[root].maxx; push_down(root); int mid=l+r>>1; if(R<=mid) return query(root<<1,l,mid,L,R); else{ if(L>mid) return query(root<<1|1,mid+1,r,L,R); else return max(query(root<<1,l,mid,L,mid),query(root<<1|1,mid+1,r,mid+1,R)); } } void updatepath_cover(int x,int y,int key){ while(top[x]!=top[y]){ if(depth[top[x]]<depth[top[y]]) swap(x,y); update_cover(1,1,n,dfn[top[x]],dfn[x],key); x=fa[top[x]]; } if(depth[x]<depth[y]) swap(x,y); update_cover(1,1,n,dfn[y]+1,dfn[x],key); } void updatepath_add(int x,int y,int key){ while(top[x]!=top[y]){ if(depth[top[x]]<depth[top[y]]) swap(x,y); update_add(1,1,n,dfn[top[x]],dfn[x],key); x=fa[top[x]]; } if(depth[x]<depth[y]) swap(x,y); update_add(1,1,n,dfn[y]+1,dfn[x],key); } int querypath(int x,int y){ int ret=0; while(top[x]!=top[y]){ if(depth[top[x]]<depth[top[y]]) swap(x,y); ret=max(ret,query(1,1,n,dfn[top[x]],dfn[x])); x=fa[top[x]]; } if(depth[x]<depth[y]) swap(x,y); ret=max(ret,query(1,1,n,dfn[y]+1,dfn[x])); return ret; } int find(int x){ return depth[edge[x<<1].to]>depth[edge[x<<1^1].to]?edge[x<<1].to:edge[x<<1^1].to; } int main(){ memset(head,-1,sizeof(head)); scanf("%d",&n); for(int i=1;i<n;++i){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z),add(y,x,z); } dfs1(1,-1); dfs2(1,1); build(1,1,n); char cz[10]; scanf("%s",cz); while(cz[0]!='S'){ int x=Read(),y=Read(); if(cz[1]=='h'){ update_cover(1,1,n,dfn[find(x)],dfn[find(x)],y); } if(cz[1]=='o'){ int k=Read(); updatepath_cover(x,y,k); } if(cz[0]=='A'){ int k=Read(); updatepath_add(x,y,k); } if(cz[0]=='M') printf("%d\n",querypath(x,y)); scanf("%s",cz); } return 0; }