树链剖分+细节。
//md居然把dfs和LCA写挂了,以后没法见人了【捂脸
这道题要求查询树上连续的一段区间,但是有起点和终点之分,所以线段树和树链剖分就不能像平时一样写;线段树还比较好写,但是树剖在查询的时候还要分靠近终点的一端和靠近起点的一端,以及最大/最小值的维护顺序,还要考虑轻重链的关系,细节还是很多的,想的时候一定要周到。
CODE:
#include<cstdio>
const int N=5e4+5;
struct edge
{
int nxt,to;
}a[N<<1];
struct tree
{
int plus,minn,maxn,maxans,minans;
}t[N<<2];
int head[N],deep[N],size[N],f[N],son[N],top[N],pos[N],s[N],w[N];
int n,m,x,y,z,num,tot;
inline int max(const int &a,const int &b){return a>b?a:b;}
inline int min(const int &a,const int &b){return a<b?a:b;}
inline void swap(int &a,int &b){a^=b,b^=a,a^=b;}
inline void add(int x,int y)
{
a[++num].nxt=head[x],a[num].to=y,head[x]=num;
a[++num].nxt=head[y],a[num].to=x,head[y]=num;
}
void dfs(int now,int fa,int depth)
{
f[now]=fa,deep[now]=depth;
size[now]=1;
int tmp=0;
for(int i=head[now];i;i=a[i].nxt)
if(a[i].to!=fa)
{
dfs(a[i].to,now,depth+1);
size[now]+=size[a[i].to];
if(size[a[i].to]>tmp) tmp=size[a[i].to],son[now]=a[i].to;
}
}
void dfs2(int now,int high)
{
top[now]=high,pos[now]=++tot;
s[tot]=w[now];
if(son[now]) dfs2(son[now],high);
for(int i=head[now];i;i=a[i].nxt)
if(a[i].to!=f[now]&&a[i].to!=son[now]) dfs2(a[i].to,a[i].to);
}
inline void update(int l,int r,int now)
{
t[now].maxans=max(0,max(t[now<<1|1].maxn-t[now<<1].minn,max(t[now<<1].maxans,t[now<<1|1].maxans)));
t[now].minans=max(0,max(t[now<<1].maxn-t[now<<1|1].minn,max(t[now<<1].minans,t[now<<1|1].minans)));
t[now].maxn=max(t[now<<1].maxn,t[now<<1|1].maxn);
t[now].minn=min(t[now<<1].minn,t[now<<1|1].minn);
}
void build(int l,int r,int now)
{
if(l==r)
{
t[now].minn=t[now].maxn=s[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,now<<1);
build(mid+1,r,now<<1|1);
update(l,r,now);
}
inline void pushdown(int now)
{
if(!t[now].plus) return;
int s1=now<<1,s2=now<<1|1,tmp=t[now].plus;
t[s1].maxn+=tmp,t[s1].minn+=tmp,t[s1].plus+=tmp;
t[s2].maxn+=tmp,t[s2].minn+=tmp,t[s2].plus+=tmp;
t[now].plus=0;
}
void change(int L,int R,int l,int r,int now,int num)
{
if(L<=l&&r<=R)
{
t[now].maxn+=num,t[now].minn+=num,t[now].plus+=num;
return;
}
int mid=(l+r)>>1;
pushdown(now);
if(L<=mid) change(L,R,l,mid,now<<1,num);
if(R>mid) change(L,R,mid+1,r,now<<1|1,num);
update(l,r,now);
}
tree ask(int L,int R,int l,int r,int now)
{
if(L<=l&&r<=R) return t[now];
int mid=(l+r)>>1;tree ans,tmp;
pushdown(now);
if(R<=mid) return ask(L,R,l,mid,now<<1);
if(L>mid) return ask(L,R,mid+1,r,now<<1|1);
ans=ask(L,R,l,mid,now<<1);tmp=ask(L,R,mid+1,r,now<<1|1);
ans.maxans=max(tmp.maxn-ans.minn,max(ans.maxans,tmp.maxans)),
ans.minans=max(ans.maxn-tmp.minn,max(ans.minans,tmp.minans)),
ans.maxn=max(ans.maxn,tmp.maxn),
ans.minn=min(ans.minn,tmp.minn);
return ans;
}
inline int LCA(int x,int y)
{
while(top[x]!=top[y])
if(deep[top[x]]>deep[top[y]]) x=f[top[x]];
else y=f[top[y]];
return deep[x]<deep[y]?x:y;
}
inline void changepath(int x,int y,int z)
{
for(;top[x]!=top[y];x=f[top[x]])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
change(pos[top[x]],pos[x],1,n,1,z);
}
int L=min(pos[x],pos[y]),R=max(pos[x],pos[y]);
change(L,R,1,n,1,z);
}
inline int askpath(int x,int y)
{
int lca=LCA(x,y),ans=0,maxn=-1e9,minn=1e9;
for(;top[x]!=top[lca];x=f[top[x]])
{
tree tmp=ask(pos[top[x]],pos[x],1,n,1);
ans=max(ans,max(tmp.minans,tmp.maxn-minn));
minn=min(minn,tmp.minn);
}
if(x!=lca)
{
tree tmp=ask(pos[lca],pos[x],1,n,1);
ans=max(ans,max(tmp.minans,tmp.maxn-minn));
minn=min(minn,tmp.minn);
}
for(;top[y]!=top[lca];y=f[top[y]])
{
tree tmp=ask(pos[top[y]],pos[y],1,n,1);
ans=max(ans,max(max(tmp.maxans,tmp.maxn-minn),max(maxn-tmp.minn,maxn-minn)));
maxn=max(maxn,tmp.maxn);
}
if(y!=lca||x==lca)
{
tree tmp=ask(pos[lca],pos[y],1,n,1);
ans=max(ans,max(max(tmp.maxans,tmp.maxn-minn),max(maxn-tmp.minn,maxn-minn)));
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<n;i++)
scanf("%d%d",&x,&y),add(x,y);
dfs(1,0,1),dfs2(1,1),build(1,n,1);
scanf("%d",&m);
while(m--)
scanf("%d%d%d",&x,&y,&z),printf("%d\n",askpath(x,y)),changepath(x,y,z);
return 0;
}