Yaoge likes to eat chicken chops late at night. Yaoge has eaten too many chicken chops, so that Yaoge knows the pattern in the world of chicken chops. There are N cities in the world numbered from 1 to N . There are some roads between some cities, and there is one and only one simple path between each pair of cities, i.e. the cities are connected like a tree. When Yaoge moves along a path, Yaoge can choose one city to buy ONE chicken chop and sell it in a city after the city Yaoge buy it. So Yaoge can get profit if Yaoge sell the chicken chop with higher price. Yaoge is famous in the world. AFTER Yaoge has completed one travel, the price of the chicken chop in each city on that travel path will be increased by V .
The first line contains an integer T (0 < T ≤ 10), the number of test cases you need to solve. For each test case, the first line contains an integer N (0 < N ≤ 50000), the number of cities. For each of the next N lines, the i-th line contains an integer W
i(0 < W
i ≤ 10000), the price of the chicken chop in city i. Each of the next N - 1 lines contains two integers X Y (1 ≤ X, Y ≤ N ), describing a road between city X and city Y . The next line contains an integer Q(0 ≤ Q ≤ 50000), the number of queries. Each of the next Q lines contains three integer X Y V(1 ≤ X, Y ≤ N ; 0 < V ≤ 10000), meaning that Yaoge moves along the path from city X to city Y , and the price of the chicken chop in each city on the path will be increased by V AFTER Yaoge has completed this travel.
For each query, output the maximum profit Yaoge can get. If no positive profit can be earned, output 0 instead.
#pragma comment(linker, "/STACK:1024000000,1024000000") //因OJ采用Windows系统,要加入这一行用于 进行手动扩栈,这样就不会引起爆栈
#include
#include
#include
#define LL long long
using namespace std;
const int N = 50005;
int num[N],deep[N],son[N],fath[N];
int p[N],top[N],pos;
int head[N], to[N << 1], next1[N << 1], tot;
void init(int n)
{
pos=0; tot=0;
memset(head,-1,sizeof(head));
}
void addEdge(const int& u, const int& v) {
to[tot] = v, next1[tot] = head[u], head[u] = tot++;
}
void addUndirEdge(const int& u, const int& v) {
addEdge(u, v), addEdge(v, u);
}
void dfs1(int u,int pre,int d)//找重边
{
num[u]=1;
deep[u]=d;
fath[u]=pre;
son[u]=-1;
for(int i=head[u]; i!=-1; i=next1[i]){
int v=to[i];
if(v==fath[u])continue;
dfs1(v,u,d+1);
num[u]+=num[v];
if(son[u]==-1||num[v]>num[son[u]])
son[u]=v;
}
}
void getpos(int u,int root)//连接重边成重链,每条重链不会相交
{
top[u]=root; p[u]=++pos;
if(son[u]==-1)
return ;
getpos(son[u],root);
for(int i=head[u]; i!=-1; i=next1[i]){
int v=to[i];
if(son[u]!=v&&v!=fath[u])
getpos(v,v);
}
}
struct tree
{
LL maxprice,minprice,addv,maxprofit0,maxprofit1;//最大价值,最小价值,子节点的每个点都需加的值,从左到右得到的最大利润,从右到左得到的最大利润
}root[N*3];
LL val[N];
LL MAX(LL a,LL b){ return a>b?a:b; }
LL MIN(LL a,LL b){ return a>b?b:a; }
//void swp(int &a,int &b){ int tt=a; a=b; b=tt; }
void pushUp(int k)
{
root[k].maxprofit0=MAX(root[k<<1].maxprofit0, root[k<<1|1].maxprofit0);
root[k].maxprofit0=MAX(root[k].maxprofit0,root[k<<1|1].maxprice-root[k<<1].minprice);
root[k].maxprofit1=MAX(root[k<<1].maxprofit1, root[k<<1|1].maxprofit1);
root[k].maxprofit1=MAX(root[k].maxprofit1,root[k<<1].maxprice-root[k<<1|1].minprice);
root[k].maxprice=MAX(root[k<<1].maxprice,root[k<<1|1].maxprice);
root[k].minprice=MIN(root[k<<1].minprice,root[k<<1|1].minprice);
}
void pushDown(int k)
{
if(root[k].addv){
root[k<<1].maxprice+=root[k].addv;
root[k<<1].minprice+=root[k].addv;
root[k<<1].addv+=root[k].addv;
root[k<<1|1].maxprice+=root[k].addv;
root[k<<1|1].minprice+=root[k].addv;
root[k<<1|1].addv+=root[k].addv;
root[k].addv=0;
}
}
void build(int l,int r,int k)
{
root[k].addv=0;
if(l==r){
root[k].maxprofit0=root[k].maxprofit1=0;
root[k].maxprice=root[k].minprice=val[l]; return ;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
pushUp(k);
}
void update(int l,int r,int k,const int L,const int R,LL c)
{
if(L<=l&&r<=R){
root[k].maxprice+=c;
root[k].minprice+=c;
root[k].addv+=c;
return ;
}
pushDown(k);
int mid=(l+r)>>1;
if(L<=mid) update(l,mid,k<<1,L,R,c);
if(mid>1 ;
if(R<=mid) return query(l,mid,k<<1,L,R,op,maxprice,minprice);
else if(mid=deep[fv]){
profit=MAX(profit, query(1,pos,1,p[fu],p[u],1,tmax,tmin) ); //当前区间段的最大利润
profit=MAX(profit, tmax-minu); //当前段的最大值-己从u点出发走过的区间段的最小值
profit=MAX(profit, maxv-tmin); //到达终点v的某一段区间的最大值-当前区间段的最小值
maxu=MAX(maxu, tmax); //u点己走过的区间段内的最大值
minu=MIN(minu, tmin); //u点己走过的区间段内的最小值
update(1,pos,1,p[fu],p[u],(LL)c); //先查之后,当前区间段的点值都加上c
u=fath[fu]; fu=top[u];
}
else{
profit=MAX(profit, query(1,pos,1,p[fv],p[v],0,tmax,tmin) );
profit=MAX(profit, maxv-tmin);
profit=MAX(profit, tmax-minu);
maxv=MAX(maxv, tmax);
minv=MIN(minv, tmin);
update(1,pos,1,p[fv],p[v],(LL)c);
v=fath[fv]; fv=top[v];
}
}
if(deep[u]>=deep[v]){
profit=MAX(profit, query(1,pos,1,p[v],p[u],1,tmax,tmin) );
profit=MAX(profit, maxv-tmin);//不要忘了这两个利润的比较
profit=MAX(profit, tmax-minu);
update(1,pos,1,p[v],p[u],(LL)c);
}
else{
profit=MAX(profit, query(1,pos,1,p[u],p[v],0,tmax,tmin) );
profit=MAX(profit, maxv-tmin);
profit=MAX(profit, tmax-minu);
update(1,pos,1,p[u],p[v],(LL)c);
}
return profit;
}
int main()
{
int T,n,q,a,b,c,price[N];
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
init(n);
for(int i=1; i<=n; i++)
scanf("%d",&price[i]);
for(int i=1; i