这基本上是一道金银分界线的题
题目大意:
给一棵树,给点权,然后查询从节点 x x x到 y y y,求最大值减最小值的 m a x max max(注意: x x x到 y y y是有方向的)。
首先不得不说,学弟nb
首先考虑方向
分为向上,和向下,即从 x x x到 L C A LCA LCA(上升),从 L C A LCA LCA到 y y y(下降)
维护每个区间的左边减右边的 m a x max max,以及右边减左边的 m a x max max,维护方法就是区间和并,因为区间修改对差没有影响,因此 p u s h d o w n pushdown pushdown照旧,但 p u s h u p pushup pushup要写成区间合并
注意在上升的时候,要右减左,下降的时候要左减右( q c h a i n qchain qchain的时候不能交换 x x x和 y y y),直接记录下来,然后进行一个合并操作即可
合并操作如下:
tree merge(tree p1,tree p2)
{
tree p;
p.sum[0]=max(p1.sum[0],p2.sum[0]);
p.sum[0]=max(p2.ma-p1.mi,p.sum[0]);
p.sum[0]=max(p.sum[0],(int)0);
p.sum[1]=max(p1.sum[1],p2.sum[1]);
p.sum[1]=max(p1.ma-p2.mi,p.sum[1]);
p.sum[1]=max(p.sum[1],(int)0);
p.ma=max(p1.ma,p2.ma);
p.mi=min(p1.mi,p2.mi);
return p;
}
总代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define int long long
//#define double long double
#define re register int
#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define P pair < int , int >
#define mk make_pair
using namespace std;
const int mod=998244353;
const int M=1e9;
const int N=2e5+5;//?????????? 4e8
struct node
{
int ver,next;
}t[N];
struct tree
{
int ma,mi,sum[2],add;
}e[N];
int a[N],w[N],dfn[N],tot,head[N];
int n,q;
int sz[N],son[N],top[N],fa[N],d[N];
int num;
void init()
{
for(re i=0;i<=n+1;i++)
{
head[i]=w[i]=a[i]=dfn[i]=sz[i]=son[i]=top[i]=0;
fa[i]=d[i]=0;
}
tot=num=0;
}
void add(int x,int y)
{
t[++tot].ver=y;
t[tot].next=head[x];
head[x]=tot;
}
void addedge(int x,int y)
{
add(x,y);add(y,x);
}
void dfs1(int x,int pre)
{
int ma=-1;
sz[x]=1;d[x]=d[pre]+1;fa[x]=pre;
for(re i=head[x];i;i=t[i].next)
{
int y=t[i].ver;
if(y==pre) continue;
dfs1(y,x);
if(ma<sz[y]) ma=sz[y],son[x]=y;
sz[x]+=sz[y];
}
}
void dfs2(int x,int pre)
{
dfn[x]=++num;
top[x]=pre;
w[num]=a[x];
if(!son[x]) return;
dfs2(son[x],pre);
for(re i=head[x];i;i=t[i].next)
{
int y=t[i].ver;
if(son[x]==y||fa[x]==y) continue;
dfs2(y,y);
}
}
void push(int p)
{
e[p].sum[0]=max(e[ls(p)].sum[0],e[rs(p)].sum[0]);
e[p].sum[0]=max(e[rs(p)].ma-e[ls(p)].mi,e[p].sum[0]);
e[p].sum[0]=max(e[p].sum[0],(int)0);
e[p].sum[1]=max(e[ls(p)].sum[1],e[rs(p)].sum[1]);
e[p].sum[1]=max(e[ls(p)].ma-e[rs(p)].mi,e[p].sum[1]);
e[p].sum[1]=max(e[p].sum[1],(int)0);
e[p].ma=max(e[ls(p)].ma,e[rs(p)].ma);
e[p].mi=min(e[ls(p)].mi,e[rs(p)].mi);
}
tree merge(tree p1,tree p2)
{
tree p;
p.sum[0]=max(p1.sum[0],p2.sum[0]);
p.sum[0]=max(p2.ma-p1.mi,p.sum[0]);
p.sum[0]=max(p.sum[0],(int)0);
p.sum[1]=max(p1.sum[1],p2.sum[1]);
p.sum[1]=max(p1.ma-p2.mi,p.sum[1]);
p.sum[1]=max(p.sum[1],(int)0);
p.ma=max(p1.ma,p2.ma);
p.mi=min(p1.mi,p2.mi);
return p;
}
void bulid(int p,int l,int r)
{
e[p].add=e[p].mi=e[p].ma=0;
for(re i=0;i<=1;i++) e[p].sum[i]=0;
if(l==r)
{
e[p].ma=e[p].mi=w[l];
return;
}
int mid=(l+r)>>1;
bulid(ls(p),l,mid);bulid(rs(p),mid+1,r);
push(p);
}
void spread(int p)
{
if(!e[p].add) return;
e[ls(p)].ma+=e[p].add;
e[ls(p)].mi+=e[p].add;
e[rs(p)].ma+=e[p].add;
e[rs(p)].mi+=e[p].add;
e[ls(p)].add+=e[p].add;
e[rs(p)].add+=e[p].add;
e[p].add=0;
}
void change(int p,int L,int R,int l,int r,int v)
{
if(L<=l&&r<=R)
{
e[p].ma+=v;
e[p].mi+=v;
e[p].add+=v;
return;
}
spread(p);
int mid=(l+r)>>1;
if(L<=mid) change(ls(p),L,R,l,mid,v);
if(mid<R) change(rs(p),L,R,mid+1,r,v);
push(p);
}
tree ask(int p,int L,int R,int l,int r)
{
if(L<=l&&r<=R) return e[p];
spread(p);
int mid=(l+r)>>1;
if(R<=mid) return ask(ls(p),L,R,l,mid);
else if(L>mid) return ask(rs(p),L,R,mid+1,r);
else return merge(ask(ls(p),L,R,l,mid),ask(rs(p),L,R,mid+1,r));
}
tree cnt[N],instack[N];
void print(tree p)
{
// puts("132f1a");
// printf("%lld %lld %lld %lld %lld\n",p.ma,p.mi,p.sum[0],p.sum[1],p.add);
}
int qchain(int x,int y,int z)
{
tree ans;
int t=0,top1=0;
while(top[x]!=top[y])
{
// cout<<"xzfcz"<<endl;
if(d[top[x]]<d[top[y]])
{
// cout<<dfn[top[y]]<<" "<<dfn[y]<<endl;
ans=ask(1,dfn[top[y]],dfn[y],1,n);
print(ans);
change(1,dfn[top[y]],dfn[y],1,n,z);
y=fa[top[y]];
instack[++top1]=ans;
}
else
{
// cout<<dfn[top[x]]<<" "<<dfn[x]<<endl;
ans=ask(1,dfn[top[x]],dfn[x],1,n);
print(ans);
change(1,dfn[top[x]],dfn[x],1,n,z);
x=fa[top[x]];
cnt[++t]=ans;
}
}
if(d[x]<d[y])
{
ans=ask(1,dfn[x],dfn[y],1,n);
change(1,dfn[x],dfn[y],1,n,z);
instack[++top1]=ans;
print(ans);
}
else
{
ans=ask(1,dfn[y],dfn[x],1,n);
change(1,dfn[y],dfn[x],1,n,z);
cnt[++t]=ans;
print(ans);
}
for(re i=1;i<=t;i++) swap(cnt[i].sum[0],cnt[i].sum[1]);
while(top1>0) cnt[++t]=instack[top1--];
tree fin;
fin.add=fin.ma=fin.sum[0]=fin.sum[1]=0;
fin.mi=1e18;
for(re i=1;i<=t;i++) fin=merge(fin,cnt[i]);
print(fin);
return fin.sum[0];
}
void solve()
{
cin>>n;
init();
for(re i=1;i<=n;i++) scanf("%lld",&a[i]);
for(re i=1;i<n;i++)
{
int x,y;
scanf("%lld%lld",&x,&y);
addedge(x,y);
}
dfs1(1,1);dfs2(1,1);bulid(1,1,n);
// for(re i=1;i<=n;i++) printf("%lld ",dfn[i]);
cin>>q;
while(q--)
{
int x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
printf("%lld\n",qchain(x,y,z));
}
}
signed main()
{
int T=1;
cin>>T;
for(int index=1;index<=T;index++)
{
// printf("Case #%lld:\n",index);
solve();
// puts("");
}
return 0;
}
/*
2
5
1
2
3
4
5
1 2
2 3
3 4
4 5
1
1 5 1
5
1
2
3
4
5
1 2
1 3
2 4
2 5
2
4 5 2
3 4 1
*/