original link - http://acm.hdu.edu.cn/showproblem.php?pid=5052
题意:
给出一棵树,点权。每次查询要从xxx走到yyy,可以在路径之前的地方取一个值v1v_1v1,之后的地方v2v_2v2,你可以得到v2−v1v_2-v_1v2−v1,当然可以不取为0。求每次得到的最大值。走完后,路径上的点权值加上vvv。
解析:
考虑用树链剖分做。
分为三种情况:
- x→lcax\to lcax→lca
- lca→ylca\to ylca→y
- x→yx\to yx→y
我们要维护区间最大值mxmxmx,最小值mimimi,往上时可得到的最大值upupup,往下时可得到的最大值downdowndown。
由于x→lcax\to lcax→lca的数组是lca→xlca\to xlca→x,所以downdowndown表示正常的mx[rs]−mi[ls]mx[rs]-mi[ls]mx[rs]−mi[ls],而upupup则相反为mx[ls]−mi[rs]mx[ls]-mi[rs]mx[ls]−mi[rs]。
最后的答案为:max(up[x→lca],down[lca→y],mx[lca→y]−mi[x→lca]max(up[x\to lca],down[lca\to y],mx[lca\to y]-mi[x\to lca]max(up[x→lca],down[lca→y],mx[lca→y]−mi[x→lca]。
想的时候,比较纠结的是路径上多个区间之间的关系。对后面来说,mimimi和mxmxmx的维护比较简单,但是upupup和downdowndown要想一下。
考虑x→lcax\to lcax→lca时,之前的结点为UUU,当前区间QQQ,此时得到的upupup应该是Q.mx−U.miQ.mx-U.miQ.mx−U.mi,合并的时候注意匹配即可。
代码:
/*
* Author : Jk_Chen
* Date : 2019-08-20-13.24.20
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
const LL mod=1e9+7;
const int maxn=5e4+5;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
/*_________________________________________________________head*/
#define rep_e(i,p,u) for(int i=head[p],u=to[i];i;i=nex[i],u=to[i])
int head[maxn],to[maxn<<1],nex[maxn<<1],now;
void add(int a,int b){
nex[++now]=head[a];head[a]=now;to[now]=b;
}
void init_edge(){
memset(head,0,sizeof head);
now=0;
}
/*_________________________________________________________edge*/
int n;
int a[maxn],w[maxn];
// 跑出树的信息
int fa[maxn],dep[maxn],siz[maxn],son[maxn];
void dfs_init(int p,int f,int deep){
fa[p]=f;
dep[p]=deep;
siz[p]=1;
son[p]=0;
int maxx=-1;
rep_e(i,p,u){
if(u==f)continue;
dfs_init(u,p,deep+1);
siz[p]+=siz[u];
if(siz[u]>maxx){
maxx=siz[u];
son[p]=u;
}
}
}
// 跑出对应dfs序
int top[maxn],id[maxn];
int cnt;
void dfs(int p,int rt){
top[p]=rt;
id[p]=++cnt;
w[cnt]=a[p];
if(!son[p])return;
// 先跑重儿子
dfs(son[p],rt);
rep_e(i,p,u){
if(u==fa[p]||u==son[p])continue;
dfs(u,u); // 不是重儿子开新链
}
}
/*_________________________________________________________init*/
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
struct node{
int mx,mi,up,down;
node(int mx=0,int mi=2e9,int up=0,int down=0):mx(mx),mi(mi),up(up),down(down){}
}tr[maxn<<2];
int laz[maxn<<2];
void Merge(node &res,node l,node r){
res.mx=max(l.mx,r.mx);
res.mi=min(l.mi,r.mi);
res.down=max(max(l.down,r.down), r.mx-l.mi);
res.up=max(max(l.up,r.up), l.mx-r.mi);
}
void build(int rt=1,int l=1,int r=n){
if(l==r){
tr[rt]=node(w[l],w[l],0,0);
laz[rt]=0;
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
Merge(tr[rt],tr[ls],tr[rs]);
laz[rt]=0;
}
void down(int rt){
if(laz[rt]){
int &val=laz[rt];
tr[ls].mx+=val;
tr[ls].mi+=val;
tr[rs].mx+=val;
tr[rs].mi+=val;
laz[ls]+=val;
laz[rs]+=val;
laz[rt]=0;
}
}
void update(int L,int R,int val,int rt=1,int l=1,int r=n){
if(l>=L&&r<=R){
tr[rt].mi+=val;
tr[rt].mx+=val;
laz[rt]+=val;
return;
}
down(rt);
if(L<=mid)update(L,R,val,ls,l,mid);
if(R>mid)update(L,R,val,rs,mid+1,r);
Merge(tr[rt],tr[ls],tr[rs]);
}
node query(int L,int R,int rt=1,int l=1,int r=n){
if(l>=L&&r<=R){
return tr[rt];
}
down(rt);
node res;
if(L<=mid)res=query(L,R,ls,l,mid);
if(R>mid)Merge(res,res,query(L,R,rs,mid+1,r));
return res;
}
/*_________________________________________________________tree*/
int solve(int x,int y,int val){
node U,D;
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]]){
Merge(U,query(id[top[x]],id[x]),U); // up l-r
update(id[top[x]],id[x],val);
x=fa[top[x]];
}
else{
Merge(D,query(id[top[y]],id[y]),D); // down r-l
update(id[top[y]],id[y],val);
y=fa[top[y]];
}
}
if(dep[x]<=dep[y]){
Merge(D,query(id[x],id[y]),D);
update(id[x],id[y],val);
}
else{
Merge(U,query(id[y],id[x]),U);
update(id[y],id[x],val);
}
return max(max(U.up,D.down), max(0,D.mx-U.mi));
}
/*_________________________________________________________solve*/
int main(){int t=rd();while(t--){
init_edge();
cnt=0;
n=rd();
rep(i,1,n)a[i]=rd();
rep(i,2,n){
int u=rd(),v=rd();
add(u,v);add(v,u);
}
int rt=1;
dfs_init(rt,0,1); // rt 0 1
dfs(rt,rt); // rt rt
build();
int m=rd();
while(m--){
int a=rd(),b=rd(),v=rd();
printf("%d\n",solve(a,b,v));
}
}}