Problem solving [CF932F Escape Through Leaf]

Original question link Given a tree, each point has a value \ (a,b \). Each time you can go from a point \ (x \) to a po...

Original question link

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 } \ limits 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 \).

Similar to \ (\ text \) 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 \) divide and conquer. There is no strict boundary between the two.

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

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; inline void read(int &x){ x=0;ch=getchar();while(ch<47)ch=getchar(); while(ch>47)x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); } inline void read_(int &x){ 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; inline void add(int x,int y) int nextnq[M],toq[M],hq[N<<2],edgq; inline void addq(int x,int y) int dfn[N],sz[N],rev[N],kk[N];ll f[N]; struct node}s[N]; struct point{ ll x,y;point()=default;point(ll _x,ll _y):x(_x),y(_y){} bool operator <=(const point &a)const point operator -(const point &a)const }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 }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){ if(x<=l&&r<=y)addq(k,i); else { int mid=(l+r)>>1; if(x<=mid)add(ls,l,mid,x,y,i); if(mid<y)add(rs,mid+1,r,x,y,i); } }//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(){ read(n);register int i; for(i=1;i<=n;++i)read_(s[i].a),kk[i]=-s[i].a; for(i=1;i<=n;++i)read_(s[i].b),s[i].i=i,f[i]=inf; for(i=1;i^n;++i)read(x),read(y),add(x,y),add(y,x); init(1,0); for(i=1;x=rev[i],i<=n;++i)q[i]=stp(s[x].b,0); sort(s+1,s+n+1);//Sorting ensures that the slope increases when querying on the segment tree for(i=1;x=s[i].i,i<=n;++i){ if(sz[x]^1)add(1,1,n,dfn[x]+1,dfn[x]+sz[x]-1,x); else f[x]=0; } solve(1,1,n); for(i=1;i<=n;++i)printf("%.0lf ",f[i]); }

7 November 2021, 15:32 | Views: 3598

Add new comment

For adding a comment, please log in
or create account

0 comments