// Hydro submission #674906969592d6097b87f718@1732839063106
/*
先看不在树上的版本 (P4025):
有 n 个怪兽,每一个怪兽有两个属性 a,b。
a 表示打败他需要扣掉 a 的体力,b 表示打败之后加的体力。
可以任意钦定挑战顺序。
我们先确定挑战顺序:
把它分成两类考虑,一种是 a<=b 打完之后加血,一种是 a>b 打完之后扣血。
我肯定是先打加血的,再打扣血的。
1. 在加血的内部,我肯定是按照 a 升序排,这样可以最大可能的保证我能活着。
2. 在扣血的内部,我们考虑正难则反,我们正着考虑是不断地扣血,那倒着考虑就是不断加血,
根据我们 1. 中的结论,应该按照 a'(其实是原来的 b) 升序排,那再反回来过来就是按照 b 降序排。
如果你一定要正着考虑的话也不是不行,假设现在有两个怪兽 (ai,bi),(aj,bj)(ai>bi,aj>bj,bj>bi)。
1. ai>aj:我先放 (aj,bj) 一定不劣,因为不仅扣的少还加的多。
2. ai<aj:此时我如果先去打 (ai,bi) 是可行的话,说明此时的血量 x>ai,但因为后面 x 会变小,所以当去打 (aj,bj) 时的血量 x'<x,但是如果 x'>aj,
那么 x 也一定 >aj,所以我先打 (aj,bj) 也一定可行,并且更优。
按照这个排序即可。
放到这题里面,因为他还给你钦定了要满足祖先关系所以不能这么排。
但是,注意到如果一个点 u 的优先级比 fa 高,那么当 fa 被选的时候,我去立刻选 u 一定不劣。
那我们就可以直接把 u 和 fa 合并成一个新的点。
我们不断从优先队列中取出优先级最高的点和他的父亲合并,最后的根节点的 a 就是答案。
现在我们只需要确定合并后的节点的 a,b 值是什么:
我们需要保证两个事情:
1. 原来会死的在合并之后依旧会死
2. 最后加的/扣的血量保持不变
会发现在取 u 和 fa 这两个点的过程中,扣血量的最大值是 max(a[fa],a[fa]-b[fa]+a[u])。
我们把这个当作合并后的节点的 a,把 max(a[fa],a[fa]-b[fa]+a[u])+b[fa]+b[u]-a[fa]-a[u] 作为合并后节点的 b 就行了。
用并查集维护即可。
*/
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
inline int read(){
int w = 1, s = 0;
char c = getchar();
for (; c < '0' || c > '9'; w *= (c == '-') ? -1 : 1, c = getchar());
for (; c >= '0' && c <= '9'; s = 10 * s + (c - '0'), c = getchar());
return s * w;
}
int n,a[N],b[N];
vector<int> G[N];
void add(int u,int v){G[u].push_back(v);}
int f[N],fa[N];
int get(int x){
return (x==fa[x])?x:(fa[x]=get(fa[x]));
}
void dfs(int u,int fa){
f[u]=fa;
for(int v:G[u]){
if(v==fa) continue;
dfs(v,u);
}
}
struct P{
int u;
};
bool operator < (const P &A,const P &B){ //重载时全都反过来
int x=A.u,y=B.u;
if(a[x]<=b[x] && a[y]>b[y]) return false;
if(a[x]>b[x] && a[y]<=b[y]) return true;
if(a[x]<=b[x]) return a[x]>a[y];
else return b[x]<b[y];
}
priority_queue<P> Q;
signed main(){
// freopen("tree.in","r",stdin);
// freopen("tree.out","w",stdout);
int T=read();
while(T--){
n=read();
a[1]=b[1]=0;
for(int i=1;i<=n;i++) G[i].clear();
for(int i=2;i<=n;i++){
a[i]=read(),b[i]=read();
Q.push({i});
}
for(int i=1;i<n;i++){
int u=read(),v=read();
add(u,v),add(v,u);
}
dfs(1,0);
for(int i=1;i<=n;i++) fa[i]=i;
while(Q.size()){
int u=Q.top().u; Q.pop();
int Fa=get(f[u]);
int ta=max(a[Fa],a[Fa]-b[Fa]+a[u]),tb=max(a[Fa],a[Fa]-b[Fa]+a[u])+b[Fa]+b[u]-a[Fa]-a[u];
a[Fa]=ta,b[Fa]=tb;
fa[u]=Fa;
}
printf("%lld\n",a[1]);
}
return 0;
}