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 }

原文地址:https://www.cnblogs.com/ShakuganSky/p/9461061.html

时间: 2024-10-05 20:25:09

Codeforces 932F - Escape Through Leaf的相关文章

CodeForces 148B Escape

Escape Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Practice CodeForces 148B Description The princess is going to escape the dragon's cave, and she needs to plan it carefully. The princess runs at vp mil

Codeforces 264A. Escape from Stones

Squirrel Liss lived in a forest peacefully, but unexpected trouble happens. Stones fall from a mountain. Initially Squirrel Liss occupies an interval [0,?1]. Next, n stones will fall and Liss will escape from the stones. The stones are numbered from

CodeForces 264A Escape from Stones dfs

题目链接:点击打开链接 题意:开始有一个区间[0,1] 每次操作在中间填i,然后选择坐半段或者右半段(给出选择的方案,然后从左到右输出填写的i) (i=1 2 3···) #include <cstdio> char s[1000005]; void dfs(int x){ if(s[x] == 0)return ; if(s[x] == 'l') { dfs(x+1); printf("%d\n", x+1); } else { printf("%d\n&quo

CF932F Escape Through Leaf(DP,斜率优化)

SB 题. 写出 DP 方程:\(f_i\) 表示从 \(i\) 跳的最小值. \(i\) 是叶子就是 \(0\),否则就是选个子树中的 \(v\),\(f_i=\min(f_v+a_ib_v)\). 至于优化,求出每个子树中的凸包就行了.启发式合并保证复杂度. 复杂度 \(O(n\log^2 n)\). 没错,我又用了回家路线那又臭又长的写法. #include<bits/stdc++.h> using namespace std; typedef long long ll; const i

Codeforces Round #463

A - Palindromic Supersequence /* 题目大意:给出一个串,构造一个包含该串的回文串 */ #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=10010; char s[N]; int main(){ scanf("%s",s); int n=strlen(s); for(int i=n-1;

CodeForces Gym 101047E Escape from Ayutthaya BFS

Escape from Ayutthaya Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Gym 101047E Description standard input/output Ayutthaya was one of the first kingdoms in Thailand, spanning since its foundation in 1350 to its collaps

Codeforces Round #162 (Div. 1) A. Escape from Stones

A. Escape from Stones time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Squirrel Liss lived in a forest peacefully, but unexpected trouble happens. Stones fall from a mountain. Initially Squ

CodeForces 1042 F Leaf Sets 贪心

Leaf Sets 题意:给你一棵树,树上有n个点,只有一条边的点叫做叶子,现在要求把所有的叶子分组,每个组内的所有叶子的距离都不能大于k. 题解: 我们可以随意找一个不是叶子的节点当做这颗树的根节点,这样这棵树中叶子就不会出现在上方了,现在我们先把所有的叶子都单独当做一个集合来. 假设现在我们在处理以u为根的这个子树信息, 我们可以得到u子树内的叶子都到u的这个地方的信息,对这些信息来说,我们把距离都sort一遍,然后看一下是不是能合并,能合并就把信息合并一下,然后在把u的信息记为 min (

[codeforces]Codeforces Global Round 1 F. Nearest Leaf

题解:  语文题????  上面说的一段代码 告诉你的是  节点编号顺序与dfs序顺序一致  也就是你  dfs序以后编号就是[1,n]  根据这个特性  那么我们只需要维护每个叶子节点到查询v的距离即可  那么我们只需要离线所有查询 然后对子树修改即可   用线段树来维护区间加和区间最小值就行 #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #inc