# Problem solving [CF932F Escape Through Leaf]

Given a tree, each point has a value \ (a,b \).
Each time you can go from a point \ (x \) to a point \ (Y \) in its subtree, the cost is \ (a_x\times b_y \).
Find the minimum cost of each node to any leaf node in its subtree.
$$n,|a_i|,|b_i|\leq 10^5$$

Let \ (f_x \) be the minimum cost of \ (x \) to any leaf node in its subtree, then there are \ (f_x = \ mathop {\ mathrm {min}} \ limits {y \ in subtree (x)} f_y + a_xb_y \).

This is an obvious slope optimization. The information of each point can be regarded as \ ((b_y,f_y) \), maintain a lower convex shell, and then cut the minimum intercept with a straight line with a slope of \ (- a_x \). This can be achieved by using lie hyper tree merging or convex hull heuristic merging without brain.

But in fact, divide and conquer can also be competent at the time of \ (O(n\log n) \).

If the subtree limit is converted to the \ (dfs \) order, the \ ((b_y,f_y) \) in \ (dfn_x+1\leq dfn_y\leq dfn_x+sz_x-1 \) can contribute to the points required by \ (x \).

Due to the interval limit and the minimum value of query information does not meet the additivity, it is natural to think of segment tree divide and conquer.

Construct a segment tree with the order of \ (dfs \) as the subscript. Mark the points on the segment tree in the interval of \ ([dfn_x+1,dfn_x+sz_x-1] \), indicating that the points in this part can be updated \ (f_x \). These tags will be \ (O(n\log n) \).

Since the \ (dfs \) order that can update \ (f_x \) points is after \ (x \), it is necessary to traverse the segment tree in the order of \ (\ text {right, left, middle} \).

Similar to \ (\ text{cdq} \) divide and conquer, after processing the right and left sides, merge and sort the point sets on both sides \ ((b_y,f_y) \) according to the abscissa, then maintain the lower convex shell of some point sets, and then find out the slope of the point \ (x \) that can be updated by this point on the line segment tree, and query on the convex shell.

In order to increase the slope of the query, you can sort by slope before and then mark it on the segment tree.

This ensures that \ (f_x \) can be updated by all points that can update it when a certain point \ (x \) is queried.

Merge and sort, maintain the lower convex shell, and the total time complexity of the query is \ (O(n\log n) \).

This can be called segment tree divide and conquer or \ (\ text{cdq} \) divide and conquer. There is no strict boundary between the two.

For the accuracy of this question card, it is better to replace \ (\ text{long long} \) with \ (\ text{double} \).

code:

#include<bits/stdc++.h>
#define ll double
using namespace std;
const int N=2e5+10,M=5e6+10;
const ll inf=1e18;char ch;
int n,m,x,y,l_,r_,tt;bool rf;
x=0;ch=getchar();while(ch<47)ch=getchar();
while(ch>47)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
}
rf=x=0;ch=getchar();while((ch<47)&&(ch^'-'))ch=getchar();
if(ch=='-')rf=1,ch=getchar();
while(ch>47)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(rf)x=-x;
}
int nextn[N],to[N],h[N],edg;
int nextnq[M],toq[M],hq[N<<2],edgq;
int dfn[N],sz[N],rev[N],kk[N];ll f[N];
struct node{int i,a,b;bool operator <(const node &x)const{return a<x.a;}}s[N];
struct point{
ll x,y;point()=default;point(ll _x,ll _y):x(_x),y(_y){}
bool operator <=(const point &a)const{return y*a.x<=x*a.y;}
point operator -(const point &a)const{return point(x-a.x,y-a.y);}
}p[N],tmp;
struct stp{//segmenttree_partition
ll x,y;stp()=default;stp(ll _x,ll _y):x(_x),y(_y){}
bool operator <(const stp &a)const{return x!=a.x?x<a.x:y>a.y;}
}q[N],q0[N];
void init(int x,int anc){
int i,y;sz[x]=1;rev[dfn[x]=++tt]=x;
for(i=h[x];y=to[i];i=nextn[i])if(y^anc)init(y,x),sz[x]+=sz[y];
}
#define ls k<<1
#define rs k<<1|1
void add(int k,int l,int r,int x,int y,int i){
else {
int mid=(l+r)>>1;
}
}//Marking is realized by adding edges here
void solve(int k,int l,int r){
int i;
if(l^r){
int mid=(l+r)>>1;
solve(rs,mid+1,r);
solve(ls,l,mid);
merge(q+l,q+mid+1,q+mid+1,q+r+1,q0+l);
for(i=l;i<=r;++i)q[i]=q0[i];
}
else q[l].y=f[rev[l]];//The interval is dfs order, corresponding to the point rev[l] on the tree
r_=0;
for(i=l;i<=r;++i){
tmp=point(q[i].x,q[i].y);
while(r_>1&&(tmp-p[r_])<=(p[r_]-p[r_-1]))--r_;
p[++r_]=tmp;
}//Lower convex hull of maintenance interval point set
l_=1;
for(i=hq[k];y=toq[i];i=nextnq[i]){
tmp=point(1,kk[y]);
while(l_<r_&&(p[l_+1]-p[l_])<=tmp)++l_;
f[y]=min(f[y],p[l_].y-p[l_].x*tmp.y);
}//Update f
}
main(){