题解:
这道题,一开始想到自然是线段树合并了,每个点维护个
f
i
,
j
f_{i,j}
fi,j表示从
j
j
j开始上到
i
i
i,其他内部配对的最小值。不过这样就要支持区间加二次函数求最大值,根据bzoj某道题的经验,显然是不能在线段树上搞的。
然后仔细观察一下,发现这个 ( h − d e p x ) (h-dep_x) (h−depx)连续,进一步发现,这是一个关于 d e p i dep_i depi的二次函数!所以启发式合并之后,我们只需要维护:一堆二次函数集体加上一个数,插入一个二次函数,维护二次函数在 x x x点的最小值。
插入不好做,不过合并两堆大小相近的二次函数集合下凸包可以做到 O ( n + m ) O(n+m) O(n+m)(当然这里我不太确定,因为二次函数有两个交点,可能还要乘个2,这样复杂度就不对了,不过网上都说是 O ( n ) O(n) O(n)的,那就当他 O ( n ) O(n) O(n)的吧),我们只需要做一下二进制分组,合并的时候类似归并排序一样,对每个分隔点下方的两个函数求交点取个 m i n min min就好了。
时间复杂度
O
(
n
log
2
n
)
O(n \log^2 n)
O(nlog2n),注意细节:
1.二次函数系数只会出现0.5,为了避免精度问题,先乘个2。
2.算交点用判别式可能会爆long long,先转成double计算。
3.分界点存long long(如果是小数则存后面的那一个整数)。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL inf=2e18;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline LL rd() {
char ch=nc(); LL i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=2e5+50;
int n,T,dep[N],sze[N],son[N];
LL c[N],h[N];
vector <int> g[N];
struct func {
LL a,b,c;
func() {}
func(LL a,LL b,LL c) : a(a),b(b),c(c) {}
friend inline bool operator ==(const func &a,const func &b) {
return (a.a==b.a && a.b==b.b && a.c==b.c);
}
inline LL f(LL v) {return a*v*v+b*v+c;}
};
struct node {
LL p;
func f;
node() {}
node(LL p,func f) : p(p),f(f) {}
friend inline bool operator ==(const node &a,const node &b) {return a.f==b.f;}
};
struct atom {
vector <node> det;
vector <func> alf;
atom() {}
atom(func v) {
det.push_back(node(1,v));
alf.push_back(v);
}
inline LL mx(int pos) {
int l=0, r=det.size()-1,ans=0;
while(l<=r) {
int mid=(l+r)>>1;
if(det[mid].p<=pos) ans=mid, l=mid+1;
else r=mid-1;
} return det[ans].f.f(pos);
}
};
inline LL calc(func a,func b,LL lim) {
func c; c.a=b.a-a.a; c.b=b.b-a.b; c.c=b.c-a.c;
LL ans=inf;
if(c.a) {
double det=(double)c.b*c.b-4*(double)c.a*c.c;
if(det<0) return inf;
double x=(-c.b+sqrt(det))/2/c.a, y=(-c.b-sqrt(det))/2/c.a;
if(x>lim && x<inf) ans=min(ans,(long long)ceil(x));
if(y>lim && x<inf) ans=min(ans,(long long)ceil(y));
} else if(c.b) {
double x=-(double)c.c/c.b;
if(x>lim && x<inf) ans=min(ans,(long long)ceil(x));
} return ans;
}
inline atom merge(atom &a,atom &b) {
atom c; vector <node> tp;
for(auto v:a.alf) c.alf.push_back(v);
for(auto v:b.alf) c.alf.push_back(v);
int x=0,y=0;
while(x<a.det.size() && y<b.det.size()) {
if(a.det[x].p<b.det[y].p) tp.push_back(a.det[x++]);
else tp.push_back(b.det[y++]);
}
while(x<a.det.size()) tp.push_back(a.det[x++]);
while(y<b.det.size()) tp.push_back(b.det[y++]);
x=0; y=0;
for(int i=0;i<tp.size();i++) {
while(x<a.det.size()-1 && a.det[x+1].p<=tp[i].p) ++x;
while(y<b.det.size()-1 && b.det[y+1].p<=tp[i].p) ++y;
LL l=tp[i].p, r=(i<tp.size()-1) ? tp[i+1].p : inf;
func u=a.det[x].f, v=b.det[y].f;
while(l<r) {
if(l>T) break;
if(u==v) {
c.det.push_back(node(l,u));
break;
}
LL m=calc(u,v,l);
LL v1=u.f(l), v2=v.f(l);
if(v1!=v2) c.det.push_back(node(l,v1>v2 ? v : u));
else {
v1=(m==inf ? u.f(T+2) : u.f((l+m-1)/2));
v2=(m==inf ? v.f(T+2) : v.f((l+m-1)/2));
c.det.push_back(node(l,v1>v2 ? v : u));
}
l=m;
}
}
c.det.erase(unique(c.det.begin(),c.det.end()),c.det.end());
return c;
}
struct bunch {
LL tag;
vector <atom> cont;
bunch() {tag=0;}
inline void add(func v) {
v.c-=tag;
atom t=atom(v);
while(cont.size() && cont.back().alf.size()==t.alf.size())
t=merge(t,cont.back()), cont.pop_back();
cont.push_back(t);
}
inline LL mx(int pos) {
LL t=inf;
for(auto &v:cont) t=min(t,v.mx(pos));
return t+tag;
}
} *f[N];
inline void dfs(int x,int fa) {
sze[x]=1; son[x]=0; f[x]=NULL;
for(auto v:g[x]) if(v^fa) {
dfs(v,x); sze[x]+=sze[v];
if(sze[son[x]]<sze[v]) son[x]=v;
}
LL sum=0;
for(auto v:g[x])
if(v^fa) sum+=f[v]->mx(dep[x]+1);
if(son[x]) {
f[x]=f[son[x]];
LL d=sum-f[x]->mx(dep[x]+1);
f[x]->tag+=d;
}
if(!f[x]) f[x]=new bunch;
f[x]->add(func(c[x],-T*c[x]*2-c[x]-2*c[x]*c[x],2*T*c[x]*dep[x]+2*T*c[x]-c[x]*dep[x]*dep[x]-c[x]*dep[x]+2*(dep[x]+1)*c[x]*c[x]-2*h[x]+sum));
LL prev=f[x]->mx(dep[x]);
for(auto u:g[x]) if(u^fa && u^son[x]) {
for(atom &v:f[u]->cont)
for(func t:v.alf) {
func y=t; y.c+=f[u]->tag;
y.c+=sum-f[u]->mx(dep[x]+1);
f[x]->add(y);
}
}
}
inline void pre(int x,int f) {
dep[x]=dep[f]+1;
for(auto v:g[x]) if(v^f) pre(v,x);
T=max(T,dep[x]);
}
inline void solve() {
n=rd(); T=0;
for(int i=1;i<=n;i++)
h[i]=rd(), c[i]=rd();
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<n;i++) {
int x=rd(), y=rd();
g[x].push_back(y);
g[y].push_back(x);
}
pre(1,0); dfs(1,0);
cout<<(long long)(f[1]->mx(1)/2)<<'\n';
}
int main() {
for(int T=rd();T;T--) solve();
}