Codeforces 932F - Escape Through Leaf

 

Problem Link:

 

http://codeforces.com/contest/932/problem/F

 


 

 

Problem Statement:

 

F. Escape Through Leaf

 

time limit per test: 3 seconds

memory limit per test:256 megabytes

input: standard input

output: standard output

 

You are given a tree with n nodes (numbered from 1 to n) rooted at node 1. Also, each node has two values associated with it. The values for i-th node are ai and bi.

 

You can jump from a node to any node in its subtree. The cost of one jump from node x to node y is the product of ax and by. The total cost of a path formed by one or more jumps is sum of costs of individual jumps. For every node, calculate the minimum total cost to reach any leaf from that node. Pay attention, that root can never be leaf, even if it has degree 1.

 

Note that you cannot jump from a node to itself.

 

Input:

 

The first line of input contains an integer n (2 ≤ n ≤ 105) — the number of nodes in the tree.

 

The second line contains n space-separated integers a1, a2, ..., an (-105  ≤  ai  ≤  105).

 

The third line contains n space-separated integers b1, b2, ..., bn (-105  ≤  bi  ≤  105).

 

Next n - 1 lines contains two space-separated integers ui and vi (1 ≤ ui, vi ≤  n) describing edge between nodes  ui and vi in the tree.

 

Output:

 

Output n space-separated integers, i-th of which denotes the minimum cost of a path from node i to reach any leaf.

 


 

 

Analysis:

 

Apparently, we should solve this problem by dynamic programming on tree, i.e. we should not calculate the minimum cost at node x until we have calculated the minimum cost for every node in the subtree rooted at node x. However, if we try to jump to every node in the subtree of node x, the program will not fit into the time limit. Therefore, we need to speed up our O(n2) dynamic programming solution into some sort of O(n logn) solution.

 

How can we optimize our solution? Let us observe the situation when we are about to calculate the minimum cost at node x. In that case, we must have determined the minimum cost for every node its subtree, i.e. we have a set {mincost(v): v in the subtree of x}. Consider what the candidates of the minimum cost of x are, we have such a set {ax*bv + mincost(v): v in the subtree of x} in which the minimum cost equals the minimal element. This form should be familiar to people with some knowledge in linear algebra: they are all in linear form, k*m + b. Then let k = bv and = mincost(v) for every node in the subtree of x, we have a set of linear functions, and we want to calculate the minimum value at the point m = ax. This can be solved by Convex Hull Trick. If you haven’t heard about it, check this link out: https://www.cnblogs.com/ShakuganSky/p/8457943.html

 

Another detail that should be mentioned is that while keeping a convex hull for every node, we need to merge these hulls when moving to their parents, and we can optimize this procedure with the “merge small to large” trick.

 


 

 

Time Complexity:

 

O(n log2n)

 


 

 

AC Code:

 

  1 #include <iostream>
  2 #include <sstream>
  3 #include <fstream>
  4 #include <string>
  5 #include <vector>
  6 #include <deque>
  7 #include <queue>
  8 #include <stack>
  9 #include <set>
 10 #include <map>
 11 #include <algorithm>
 12 #include <functional>
 13 #include <utility>
 14 #include <bitset>
 15 #include <cmath>
 16 #include <cstdlib>
 17 #include <ctime>
 18 #include <cstdio>
 19 #include <memory.h>
 20 #include <iomanip>
 21 #include <unordered_set>
 22 #include <unordered_map>
 23 using namespace std;
 24 
 25 #define MP make_pair
 26 #define FS first
 27 #define SC second
 28 #define LB lower_bound
 29 #define PB push_back
 30 #define lc p*2+1
 31 #define rc p*2+2
 32 
 33 typedef long long ll;
 34 typedef pair<int,int> pi; 
 35 
 36 class line{
 37     public: 
 38         ll k,m;
 39         bool operator< (const line &o) const{
 40             return k<o.k||(k==o.k&&m<o.m);
 41         }
 42         bool operator== (const line &o) const{
 43             return k==o.k&&m==o.m;
 44         }
 45 };
 46 
 47 const int Maxn=1e5+5;
 48 const ll INF=1e18+5;
 49 
 50 int n,u,v;
 51 int a[Maxn],b[Maxn],pt[Maxn]; //pt[a] (pointer of 'a') is to store the cell in which the set of all current lines(linear functions) of the subtree of 'a' is stored.
 52 vector<int> adj[Maxn];
 53 ll dp[Maxn];
 54 set<line> s[Maxn];
 55 
 56 bool check(line l1,line l2,line l3){ //determine if l2 can be deleted from the set of lines
 57     double d=1.0*(l3.k-l1.k)*(l2.m-l1.m)-1.0*(l2.k-l1.k)*(l3.m-l1.m); //determine if the intersection of l3 and l1 lies left to the intersection of l2 and l1
 58     if(d>=0) return true; //if so, l2 can be deleted
 59     return false;
 60 }
 61 
 62 void insert(int id,line o){//insert line o into the set with an id
 63     if(s[id].size()<2){
 64         s[id].insert(o);
 65         return;
 66     }
 67     set<line>::iterator r=s[id].LB(o),l=r,t;
 68     if(r!=s[id].end()&&*r==o) return; //determine if line o already exists in the set 
 69     if(l!=s[id].begin()){
 70         l--;
 71         if(r!=s[id].end()&&check(*l,o,*r)) return; //determine if line o should be inserted
 72         s[id].insert(o);
 73         while(l!=s[id].begin()){
 74             t=l--;
 75             if(check(*l,*t,o)){ //delete extra lines with slope less than line o
 76                 s[id].erase(t);
 77             }
 78             else break;
 79         }
 80     }
 81     if(r!=s[id].end()){
 82         t=r++;
 83         while(r!=s[id].end()){
 84             if(check(o,*t,*r)){ //delete extra lines with slope greater than line o
 85                 s[id].erase(t);
 86                 t=r++;
 87             }
 88             else break;
 89         }
 90     }
 91 }
 92 
 93 ll gety(line o,int x){ //get the value y=f(x) for linear function o
 94     return o.m+(ll)x*o.k;
 95 }
 96 
 97 ll calc(int id,int x){
 98     int lb=-Maxn,ub=Maxn+1,mi; //perform a binary search on slope
 99     set<line>::iterator it;
100     while(ub-lb>1){
101         mi=(ub+lb)>>1;
102         it=s[id].LB(line{mi,INF});
103         if(it!=s[id].begin()&&gety(*prev(it),x)<gety(*it,x)) ub=mi; //determine the direction of binary search
104         else lb=mi;
105     }
106     it=s[id].LB(line{lb,INF}); //get the line where we can get the least value at pos=x
107     return gety(*it,x);
108 }
109 
110 void merge(int id1,int id2){
111     for(auto v:s[id1]){
112         insert(id2,v);
113     }
114 }
115 
116 void dfs(int now,int pre){
117     int weight=0,big=now; //find a heavy children and merge all the light children's line set to the heavy children's line set
118     for(auto nxt:adj[now]){
119         if(nxt!=pre){
120             dfs(nxt,now);
121             if(s[pt[nxt]].size()>weight){
122                 weight=s[pt[nxt]].size();
123                 big=nxt;
124             }
125         }
126     }
127     pt[now]=pt[big];//set pointer of current node to the pointer of the heavy children, since we are going to merge the other light children to the set
128     if(big==now){//the node is a leaf; initialize the leaf
129         dp[now]=0;
130         pt[now]=now;
131         insert(now,line{-Maxn,INF});
132         insert(now,line{Maxn,INF});
133         insert(now,line{b[now],0});
134         return;
135     }
136     for(auto nxt:adj[now]){
137         if(nxt!=pre&&nxt!=big){
138             merge(pt[nxt],pt[big]); //merge
139         }
140     }
141     dp[now]=calc(pt[now],a[now]); //find the minimum value of all functions of subtrees at pos=a[now]
142     insert(pt[now],line{b[now],dp[now]}); //insert the new line into the set
143 }
144 
145 int main(){
146     scanf("%d",&n);
147     for(int i=1;i<=n;i++)scanf("%d",a+i);
148     for(int i=1;i<=n;i++)scanf("%d",b+i);
149     for(int i=1;i<n;i++){
150         scanf("%d%d",&u,&v);
151         adj[u].PB(v);
152         adj[v].PB(u);
153     }
154     dfs(1,1);
155     for(int i=1;i<=n;i++)printf("%I64d ",dp[i]);printf("\n");
156 return 0;
157 }
View Code

 

posted @ 2018-08-11 20:54  ShakuganSky  阅读(276)  评论(0编辑  收藏  举报