Description
为了提高智商,ZJY准备去往一个新世界去旅游。这个世界的城市布局像一棵树。每两座城市之间只有一条路径可以互达。每座城市都有一种宝石,有一定的价格。ZJY为了赚取最高利益,她会选择从A城市买入再转手卖到B城市。由于ZJY买宝石时经常卖萌,因而凡是ZJY路过的城市,这座城市的宝石价格会上涨。让我们来算算ZJY旅游完之后能够赚取的最大利润。(如a城市宝石价格为v,则ZJY出售价格也为v)
1≤ N≤50000, 1≤Q ≤50000
Solution
一开始并没有甚么思路
注意到这个树上路径区间加的操作,我们可以上树链剖分
考虑怎么维护答案。我们在线段树上记录最大值、最小值、沿dfs序方向走的答案、逆dfs序方向走的答案
询问的时候把路径上连续的线段树区间合并起来。注意到一条路径(x,y)从x到lca和lca到y是反向的,因此我们拆成两条链来做就可以了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
using std:: max;
using std:: min;
const int INF=0x3f3f3f3f;
const int N=50005;
struct edge {int y,next;} e[N*2];
struct treeNode {int max,min,ans1,ans2;} rec[N<<2];
int bl[N],pos[N],dfn[N],tag[N<<2],a[N];
int size[N],fa[N],dep[N];
int ls[N],edCnt;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}
void dfs1(int now) {
size[now]=1;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa[now]) continue;
fa[e[i].y]=now; dep[e[i].y]=dep[now]+1;
dfs1(e[i].y); size[now]+=size[e[i].y];
}
}
void dfs2(int now,int up) {
bl[now]=up; dfn[pos[now]=++pos[0]]=now;
int mx=0;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y!=fa[now]&&size[e[i].y]>size[mx]) mx=e[i].y;
}
if (!mx) return ;
dfs2(mx,up);
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y!=fa[now]&&e[i].y!=mx) dfs2(e[i].y,e[i].y);
}
}
treeNode merge(treeNode a,treeNode b) {
treeNode ret;
ret.max=max(a.max,b.max);
ret.min=min(a.min,b.min);
ret.ans1=max(max(a.ans1,b.ans1),a.max-b.min);
ret.ans2=max(max(a.ans2,b.ans2),b.max-a.min);
return ret;
}
void push_up(int now) {
rec[now]=merge(rec[now<<1],rec[now<<1|1]);
}
void push_down(int now) {
if (!tag[now]) return ;
int w=tag[now]; tag[now]=0;
tag[now<<1]+=w; tag[now<<1|1]+=w;
rec[now<<1].max+=w; rec[now<<1|1].max+=w;
rec[now<<1].min+=w; rec[now<<1|1].min+=w;
}
void modify(int now,int tl,int tr,int l,int r,int v) {
if (tl==l&&tr==r) {
rec[now].max+=v; rec[now].min+=v;
return (void) (tag[now]+=v);
}
push_down(now);
int mid=(tl+tr)>>1;
if (r<=mid) modify(now<<1,tl,mid,l,r,v);
else if (l>mid) modify(now<<1|1,mid+1,tr,l,r,v);
else {
modify(now<<1,tl,mid,l,mid,v);
modify(now<<1|1,mid+1,tr,mid+1,r,v);
}
push_up(now);
}
treeNode query(int now,int tl,int tr,int l,int r) {
if (tl==l&&tr==r) return rec[now];
int mid=(tl+tr)>>1;
push_down(now);
if (r<=mid) return query(now<<1,tl,mid,l,r);
if (l>mid) return query(now<<1|1,mid+1,tr,l,r);
treeNode qx=query(now<<1,tl,mid,l,mid),qy=query(now<<1|1,mid+1,tr,mid+1,r);
return merge(qx,qy);
}
void change(int x,int y,int v) {
for (;bl[x]!=bl[y];) {
if (dep[bl[x]]<dep[bl[y]]) std:: swap(x,y);
modify(1,1,pos[0],pos[bl[x]],pos[x],v);
x=fa[bl[x]];
}
if (pos[x]>pos[y]) std:: swap(x,y);
modify(1,1,pos[0],pos[x],pos[y],v);
}
int get_lca(int x,int y) {
for (;bl[x]!=bl[y];) {
if (dep[bl[x]]<dep[bl[y]]) std:: swap(x,y);
x=fa[bl[x]];
}
return (dep[x]<dep[y])?x:y;
}
void solve(int x,int y) {
int lca=get_lca(x,y);
treeNode a,b; a=b=(treeNode) {-INF,INF,-INF,-INF};
if (x!=lca) {
for (;bl[x]!=bl[lca];) {
a=merge(query(1,1,pos[0],pos[bl[x]],pos[x]),a);
x=fa[bl[x]];
}
a=merge(query(1,1,pos[0],pos[lca],pos[x]),a);
}
if (y!=lca) {
for (;bl[y]!=bl[lca];) {
b=merge(query(1,1,pos[0],pos[bl[y]],pos[y]),b);
y=fa[bl[y]];
}
b=merge(query(1,1,pos[0],pos[lca],pos[y]),b);
}
int ans=max(max(a.ans1,b.ans2),std:: max(b.max-a.min,0));
printf("%d\n", ans);
}
void build(int now,int tl,int tr) {
rec[now]=(treeNode) {-INF,INF,-INF,-INF};
if (tl==tr) {
rec[now].max=rec[now].min=a[dfn[tl]];
return ;
}
int mid=(tl+tr)>>1;
build(now<<1,tl,mid); build(now<<1|1,mid+1,tr);
push_up(now);
}
int main(void) {
int n=read();
rep(i,1,n) a[i]=read();
rep(i,2,n) add_edge(read(),read());
dfs1(dep[1]=1); dfs2(1,1);
build(1,1,n);
// rep(i,1,n) modify(1,1,n,pos[i],pos[i],a[i]);
for (int T=read();T--;) {
int x=read(),y=read(),v=read();
solve(x,y);
change(x,y,v);
}
return 0;
}