题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4010
题目描述:输入一棵树,然后有4种操作
1. 连接 a b 2. 断开 a b 3.给a 到 b的路径上每个点增加一个值 w 4.查询 a到 b路径上的最大值
解题思路:动态树(LCT)本题几乎完全按照kuangbin大神的博客上的思路写的,没办法,本弱刚刚学lct,掌握不好,尤其是不会处理 a到 b的路径问题,有一个小小的思路,最终证明也是正确的。求 u和 v的LCA,先Access(v),也就是打通根到v的这条链。然后就类似Access(u)的过程,注意只是类似。就是不断地向上找 u到根的链,一旦发现某条链的father已经为空(也就是说这棵树的根一定在这条链上!!)那么这时的那个点就是LCA(u,v)
就如下图,Access(v)之后,红色的边就是preferred edge,也就是维护在splay里面的边
下面就是类似Access(u)一样,从 u向上找,直到找到lca(详见代码)
再次感谢kuangbin巨巨
//#pragma comment(linker,"/STACK:102400000,102400000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define ll long long
#define db double
#define PB push_back
#define lson k<<1
#define rson k<<1|1
using namespace std;
const int N = 300005;
const int INF = 2000000000;
int ch[N][2],pre[N],key[N];
int add[N],rev[N],Max[N];
bool rt[N];
void update_add(int r,int d)
{
if(!r) return;
key[r]+=d,add[r]+=d,Max[r]+=d;
}
void update_rev(int r)
{
if(!r) return;
swap(ch[r][0],ch[r][1]);
rev[r]^=1;
}
void push_down(int r)
{
if(add[r])
{
update_add(ch[r][0],add[r]);
update_add(ch[r][1],add[r]);
add[r]=0;
}
if(rev[r])
{
update_rev(ch[r][0]),update_rev(ch[r][1]);
rev[r]=0;
}
}
void push_up(int r)
{
Max[r]=max(max(Max[ch[r][0]],Max[ch[r][1]]),key[r]);
}
void rotate(int x)
{
int y=pre[x],d=ch[y][1]==x;
ch[y][d]=ch[x][!d],pre[ch[y][d]]=y;
pre[x]=pre[y],pre[y]=x;
ch[x][!d]=y;
if(rt[y]) rt[y]=false,rt[x]=true;
else ch[pre[x]][ch[pre[x]][1]==y]=x;
push_up(y);
}
void P(int r)
{
if(!rt[r]) P(pre[r]);
push_down(r);
}
void Splay(int r)
{
P(r);
while(!rt[r])
{
int f=pre[r],ff=pre[f];
if(rt[f]) rotate(r);
else if((ch[ff][1]==f)==(ch[f][1]==r))
rotate(f),rotate(r);
else rotate(r),rotate(r);
}
push_up(r);
}
int Access(int x)
{
int y=0;
for(;x;x=pre[y=x])
{
Splay(x);
rt[ch[x][1]]=true,rt[ch[x][1]=y]=false;
push_up(x);
}
return y;
}
bool judge(int u,int v)
{
while(pre[u]) u=pre[u];
while(pre[v]) v=pre[v];
return u==v;
}
void mroot(int r)
{
Access(r);
Splay(r);
update_rev(r);
}
void lca(int &u,int &v)
{
Access(v),v=0;
while(u)
{
Splay(u);
if(!pre[u]) return;
rt[ch[u][1]]=true;
rt[ch[u][1]=v]=false;
push_up(u);
u=pre[v=u];
}
}
void link(int u,int v)
{
if(judge(u,v))
{
puts("-1");
return;
}
mroot(u);
pre[u]=v;
}
void cut(int u,int v)
{
if(u==v||!judge(u,v))
{
puts("-1");
return;
}
mroot(u);
Splay(v);
pre[ch[v][0]]=pre[v];
rt[ch[v][0]]=true;
pre[v]=ch[v][0]=0;
push_up(v);
}
void ADD(int u,int v,int w)
{
if(!judge(u,v))
{
puts("-1");
return;
}
lca(u,v);
update_add(ch[u][1],w),update_add(v,w);
key[u]+=w;
push_up(u);
}
void query(int u,int v)
{
if(!judge(u,v))
{
puts("-1");
return;
}
lca(u,v);
printf("%d\n",max(max(Max[ch[u][1]],Max[v]),key[u]));
}
int head[N],to[N<<1],next[N<<1],nedge;
void add_edge(int a,int b)
{
to[nedge]=b,next[nedge]=head[a],head[a]=nedge++;
}
void dfs(int k)
{
for(int i=head[k];i>=0;i=next[i])
{
if(pre[to[i]]!=0) continue;
pre[to[i]]=k;
dfs(to[i]);
}
}
void getint(int &x)
{
char c=getchar();
while(!(c>='0'&&c<='9')) c=getchar();
x=c-'0';
while((c=getchar())>='0'&&c<='9') x=x*10+c-'0';
}
int main()
{
#ifdef PKWV
freopen("in.in","r",stdin);
#endif // PKWV
int n,q;
while(scanf("%d",&n)+1)
{
for(int i=0;i<=n;i++)
{
ch[i][0]=ch[i][1]=0;
pre[i]=0,head[i]=-1;
add[i]=0,rev[i]=0,rt[i]=true;
}
nedge=0;
Max[0]=-INF;
for(int i=1;i<n;i++)
{
int u,v;
getint(u),getint(v);
add_edge(u,v),add_edge(v,u);
}
for(int i=1;i<=n;i++)
{
getint(key[i]);
Max[i]=key[i];
}
pre[1]=-1;
dfs(1);
pre[1]=0;
getint(q);
while(q--)
{
int op;
getint(op);
int x,y;
if(op==1)
{
getint(x),getint(y);
link(x,y);
}else if(op==2)
{
getint(x),getint(y);
cut(x,y);
}else if(op==3)
{
int w;
getint(w),getint(x),getint(y);
ADD(x,y,w);
}else
{
getint(x),getint(y);
query(x,y);
}
}
puts("");
}
return 0;
}