传送门:HDU5052
【题意】一颗N结点的树,M个操作(x,y,v)在路径x->y上进行一次买卖操作,买下一个结点的物品价格,在后面某个结点的价格卖出。
【分析】就是路径x->y上找出max{ai-aj};i > j.如果是单条链(也就是一个区间)上,那么直接用线段树维护区间最大最小值,以及两个方向(正反)的答案即可。合并的时候ans1(从左到右)=max(max(l.ans1,r.ans1), r.mx-l.mi),反方向同理。
但是这里是在树上,最容易想到的是树链剖分+线段树(大神都用动态树了,本渣不会)。然而以前我用的树链剖分模板是使用swap交换的,以至于我分不清是左右那一边的链了,悲剧了2天,最终还是换了种写法,不交换了,直接记录左右两边就好了。其实不难,悲剧我写了两天。
【AC CODE】3884ms
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 50000+10;
char buf[MAXN*2], *ps = buf, *pe = buf+1;//ps当前读取到的开头指针,pe当前缓存结尾指针
inline void rnext(){
if(++ps == pe)
pe = (ps = buf)+fread(buf,1,sizeof(buf),stdin);
}
inline int in()
{
int ans = 0;
if(ps == pe) return -1; //判断是否到文件结尾
do{
rnext();
}while(!isdigit(*ps) && ps != pe);
if(ps == pe) return -1;//判断是否到文件结尾
do
{
ans = (ans<<1)+(ans<<3)+*ps-48;
rnext();
}while(isdigit(*ps) && ps != pe);
return ans;
}
int head[MAXN],to[MAXN<<1],nxt[MAXN<<1],tol;
void add_edge(int u, int v)
{
nxt[tol] = head[u],to[tol] = v;
head[u] = tol++;
}
int fa[MAXN],dep[MAXN],sz[MAXN],son[MAXN];
void dfs1(int u)
{
int num = 0;
sz[u] = 1;
for(int i = head[u]; ~i; i = nxt[i])
{
int v = to[i];
if(v == fa[u]) continue;
fa[v] = u;dep[v] = dep[u]+1;
dfs1(v);
sz[u] += sz[v];
if(sz[v] > num) num = sz[v],son[u] = v;
}
}
int top[MAXN],tree[MAXN],pre[MAXN],cnt;
void dfs2(int u, int num)
{
tree[u] = cnt;pre[cnt++] = u;top[u] = num;
if(-1 == son[u]) return;
dfs2(son[u],num);
for(int i = head[u]; ~i; i = nxt[i])
{
int v = to[i];
if(v != fa[u] && son[u] != v) dfs2(v,v);
}
}
int lmx[MAXN<<1],rmx[MAXN<<1],mi[MAXN<<1],mx[MAXN<<1],add[MAXN<<1], a[MAXN];
inline int id(int x, int y){return x+y|x!=y;}
void push_up(int x, int y, int m)
{
int u = id(x,y),l = id(x,m), r = id(m+1,y);
mi[u] = min(mi[l],mi[r]);mx[u] = max(mx[l],mx[r]);
lmx[u] = max(max(lmx[l],lmx[r]),mx[r]-mi[l]);
rmx[u] = max(max(rmx[l],rmx[r]),mx[l]-mi[r]);
}
void bulid(int x, int y)
{
if(x == y)
{
int u = id(x,y);
mi[u] = mx[u] = a[pre[x]];
lmx[u] = rmx[u] = 0;
return;
}
int m = (x+y)>>1;
bulid(x,m);
bulid(m+1,y);
push_up(x,y,m);
}
void push_down(int x, int y, int m)
{
int u = id(x,y),l = id(x,m), r = id(m+1,y);
if(add[u])
{
add[l] += add[u];
mi[l] += add[u];
mx[l] += add[u];
add[r] += add[u];
mi[r] += add[u];
mx[r] += add[u];
add[u] = 0;
}
}
void update(int x, int y, int ql, int qr, int v)
{
if(ql <= x && y <= qr)
{
int u = id(x,y);
mi[u] += v;mx[u] += v;
add[u] += v;
return;
}
int m = (x+y)>>1;
push_down(x,y,m);
if(ql <= m) update(x,m,ql,qr,v);
if(qr > m) update(m+1,y,ql,qr,v);
push_up(x,y,m);
}
struct NODE{
int ans,mi,mx;
NODE(){
ans = mx = 0;
mi = INF;
}
};
void merge(NODE &ans,const NODE &l, const NODE &r, bool lf)
{
ans.ans = max(max(l.ans,r.ans),lf?r.mx-l.mi:l.mx-r.mi);
ans.mi = min(l.mi,r.mi);ans.mx = max(l.mx,r.mx);
}
NODE query(int x, int y, int ql, int qr, bool lf)
{
if(ql <= x && y <= qr)
{
int u = id(x,y);
NODE tmp;
tmp.mi = mi[u], tmp.mx = mx[u];
tmp.ans = lf?lmx[id(x,y)]:rmx[id(x,y)];
return tmp;
}
int m = (x+y)>>1;
NODE ans;
push_down(x,y,m);
if(ql <= m && qr > m)
{
NODE l = query(x,m,ql,qr,lf),r = query(m+1,y,ql,qr,lf);
merge(ans,l,r,lf);
}
else if(ql <= m) ans = query(x,m,ql,qr,lf);
else if(qr > m) ans = query(m+1,y,ql,qr,lf);
push_up(x,y,m);
return ans;
}
void init(int rt)
{
clc(son,-1);
dep[rt] = 0,fa[rt] = -1;
dfs1(rt);
cnt = 0;
dfs2(rt,rt);
clc(add,0);
bulid(0,cnt-1);
}
void tcp_update(int x, int y, int v)
{
int f1 = top[x],f2 = top[y];
while(f1 != f2)
{
if(dep[f1] < dep[f2]) swap(f1,f2),swap(x,y);
update(0,cnt-1,tree[f1],tree[x],v);
x = fa[f1], f1 = top[x];
}
if(dep[x] > dep[y]) swap(x,y);
update(0,cnt-1,tree[x],tree[y],v);
}
int tcp_query(int x, int y)
{
NODE ans,ax,ay;
int f1 = top[x],f2 = top[y];
while(f1 != f2)
{
if(dep[top[x]] < dep[top[y]])//LCA(x,y)右边
{
merge(ay,query(0,cnt-1,tree[top[y]],tree[y],1),ay,1);
y = fa[f2];f2 = top[y];
}
else//LCA(x,y)左边
{
merge(ax,query(0,cnt-1,tree[top[x]],tree[x],0),ax,0);
x = fa[f1], f1 = top[x];
}
}
if(dep[x] < dep[y]) merge(ay,query(0,cnt-1,tree[x],tree[y],1),ay,1);
else merge(ax,query(0,cnt-1,tree[y],tree[x],0),ax,0);
merge(ans,ax,ay,1);
return ans.ans;
}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
int t = in();
while(t--)
{
int n = in();
repe(i,1,n) a[i] = in();
clc(head,-1);tol = 0;
rep(i,1,n)
{
int u = in(),v = in();
add_edge(u,v);
add_edge(v,u);
}
init(1);
int q = in();
while(q--)
{
int x = in(),y = in(),v = in();
printf("%d\n", tcp_query(x,y));
tcp_update(x,y,v);
}
}
return 0;
}