每次写LCT的过程都比较痛苦,这次也不例外,虽然花的时间不到一小时。
但是这样一道连反转标记都没有带的LCT写那么痛苦也着实不应该啊。
这道题要求支持一下操作:
QMAX(a,b): 求点a,b路径上的最大权值
QSUM(a,b): 求点a,b路径上的权值和
CHANGE(a,b):将a点的权值修改为b
一看就是比较裸的LCT了,实际上连Link和Cut的操作都不用写,倒是更像单纯的树链剖分。
QMAX操作和QSUM操作类似,就是对两个点分别进行Access操作,然后就可以得到lca以及我们想要的信息。
当年Access的这个作用曾让我惊叹。。所以为了方便理解,我画了一下大概的图。
从图中我们看到:Access(u)让我们把从根节点到节点u的路径上的点并为同一树链。
而在下一次Access(v)的过程中,显然会把图中划去的边断开,断开的边旁边就是lca!
所以我们可以这么做:
先Access(u),保证lca到根节点的路径上的点在一个树链中。
再Access(v),此时该树链的根节点(树链在实现中是Splay树)显然应该就是lca,
因为观察Access的过程我们可以发现,*每一次我们都会将当前点父节点Splay到树链根部并将当前节点作为它的右儿子。
所以在Access(v)时,由于之前的Access(u),root->lca这条路上已经属于同一树链,所以在最后一次Splay时,我们实际
上Splay的就是lca,为什么?请仔细思考*处。
于是做法也就比较清晰了,QMAX和QSUM其实类似,所以维护等操作都可以一起做。
码量虽然不多。。但也不算少,所以需要足够细心。
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Code:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=100100;
const int INF=~0u>>1;
#define L(p) T[T[p].s[0]]
#define R(p) T[T[p].s[1]]
#define F(p) T[T[p].f]
int n; char opt[10];
struct BST{
int maxv,sumv,v;
int s[2],f,ws;
BST(){
sumv=0; maxv=-INF;
s[0]=s[1]=f=ws=0;
}
}T[N];
struct list{
int p;
list *next;
list* Set(int _p,list* _next){
p=_p; next=_next;
return this;
}
}E[N],*head[N];int edge=0;
bool isroot(int p){
return (F(p).s[0]!=p&&F(p).s[1]!=p);
}
void MT(int p){
if (!p) return;
T[p].sumv=L(p).sumv+R(p).sumv+T[p].v;
T[p].maxv=max(max(L(p).maxv,R(p).maxv),T[p].v);
}
void Sets(int f,int p,int ws){T[T[p].f=f].s[T[p].ws=ws]=p;}
void Rot(int p){
int f=T[p].f,pf=F(p).f,ws=T[p].ws;
if (!isroot(f)) Sets(pf,p,F(p).ws);else T[p].f=T[f].f;
if (T[p].s[ws^1]) Sets(f,T[p].s[ws^1],ws);else T[f].s[ws]=0;
Sets(p,f,ws^1);
MT(f); MT(p); MT(pf);
}
void Splay(int p){
for(;!isroot(p);Rot(p))
if(!isroot(T[p].f)){
if(F(p).ws==T[p].ws) Rot(T[p].f);
else Rot(p);
}
}
int Access(int x){
int last=0;
for(;x;x=T[x].f){
Splay(x);
Sets(x,last,1);
MT(last=x);
}return last;
}
int qmax(int u,int v){
Access(u);
int lca=Access(v);
Splay(u);
if(lca==u) return max(T[lca].v,R(lca).maxv);
else return max(T[lca].v,max(T[u].maxv,R(lca).maxv));
}
int qsum(int u,int v){
Access(u);
int lca=Access(v);
Splay(u);
if(lca==u) return T[lca].v+R(lca).sumv;
else return (T[lca].v+R(lca).sumv+T[u].sumv);
}
void change(int p,int v){
Splay(p);
T[p].v=v;
MT(p);
}
void Addedge(int u,int v){
head[u]=(E+(edge++))->Set(v,head[u]);
head[v]=(E+(edge++))->Set(u,head[v]);
}
void dfs(int p,int f){
T[p].f=f;
for(list *t=head[p];t;t=t->next)
if(t->p!=f) dfs(t->p,p);
}
int main(){
freopen("1036.in","r",stdin);
freopen("1036.out","w",stdout);
scanf("%d",&n);
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
Addedge(u,v);
}dfs(1,0);
for(int i=1,v;i<=n;i++){
scanf("%d",&v);
T[i].v=T[i].maxv=T[i].sumv=v;
}
int a,b,m;
scanf("%d",&m);
while(m--){
scanf("%s",opt);
scanf("%d%d",&a,&b);
if(opt[1]=='H') change(a,b);
else if(opt[1]=='S') printf("%d\n",qsum(a,b));
else printf("%d\n",qmax(a,b));
}
return 0;
}