第一行两个数n<=100000、p<=10,代表树上点的个数以及题中所提及的常数p。 接下来n行,第i行有两个数字a[i]<10^6、fa[i]Output每组数据输出一行为最短耗时。Input示例10 2 833 0 2076 1 5759 1 5671 3 6642 2 3712 4 8737 1 5139 6 8800 1 6638 1Output示例849
这道题蕴含一种思想:从特殊到一般 , 直接考虑树形结构会发现无从下手 , 但从链 ---> 树进行转换 , 就可以发现正解
对于一条链:f[i] = max(f[i] , f[j] + a[j] + (i - j)^p) , 显然算法是n^2的 , 转化成树 ,就是将根节点到每个叶子节点的路径单独考虑,最后统计每个叶子节点的
最小值。
可是如何优化时间复杂度呢?
由于转移方程中有一部分是指数形式的,呈暴增趋势 , 但存在一种情况,就是(i - j ^ p)较小, 但a[j]较大所以必然存在一个临界值 , 这也依赖于一个性质:
对于节点i , j , x, deep[i] < deep[j] < deep[x] , 若f[i] + cost(i --> x) >= f[j] + cost(j --> x) , 显然在j包含的所有叶子节点不可能从i转移过来,而且要注意为什么是
等号:如果两种花费相同 , 显然深度越大的使得(a - b)^ p部分 更小 , 所以淘汰i。
上述操作可以用队列来完成 , 即不断去掉队首的元素,那么可不可以也去掉队尾的一些元素呢
还是上述性质 , 对于队列中末尾两个节点 , 可以找上面说的那个临界值 ,同时这找出队尾节点和当前节点的临界值 , 判断一下 , 所谓临界值V(i , j)(i和j的临界值 , deep[i] < deep[j])的含义就是 :编号大于等于 临界值的
节点从j转移过来最有 , 编号 小于临界值的节点从i好转移过来最优 , 寻找方法当然是二分答案了(EFDA), 若V(que[tail - 1] , que[tail]) > V(que[tail] , x) , 说明que[tail]的节点无论如何都不会最优(画图理解),这样就可以不断删除队尾元素了。
这些操作的思想就是发现单调性 , 运用斜率优化类似操作进行优化 。
总的来说是一道不错的有思想的题目。
/*
51 nod 1789
这道题蕴含一种思想:从特殊到一般 , 直接考虑树形结构会发现无从下手 , 但从链 ---> 树进行转换 , 就可以发现正解
对于一条链:f[i] = max(f[i] , f[j] + a[j] + (i - j)^p) , 显然算法是n^2的 , 转化成树 ,就是将根节点到每个叶子节点的路径单独考虑,最后统计每个叶子节点的
最小值。
可是如何优化时间复杂度呢?
由于转移方程中有一部分是指数形式的,呈暴增趋势 , 但存在一种情况,就是(i - j ^ p)较小, 但a[j]较大所以必然存在一个临界值 , 这也依赖于一个性质:
对于节点i , j , x, deep[i] < deep[j] < deep[x] , 若f[i] + cost(i --> x) >= f[j] + cost(j --> x) , 显然在j包含的所有叶子节点不可能从i转移过来,而且要注意为什么是
等号:如果两种花费相同 , 显然深度越大的使得(a - b)^ p部分 更小 , 所以淘汰i。
上述操作可以用队列来完成 , 即不断去掉队首的元素,那么可不可以也去掉队尾的一些元素呢
还是上述性质 , 对于队列中末尾两个节点 , 可以找上面说的那个临界值 ,同时这找出队尾节点和当前节点的临界值 , 判断一下 , 所谓临界值V(i , j)(i和j的临界值 , deep[i] < deep[j])的含义就是 :编号大于等于 临界值的
节点从j转移过来最有 , 编号 小于临界值的节点从i好转移过来最优 , 寻找方法当然是二分答案了(EFDA), 若V(que[tail - 1] , que[tail]) > V(que[tail] , x) , 说明que[tail]的节点无论如何都不会最优(画图理解),这样就可以不断删除队尾元素了。
这些操作的思想就是发现单调性 , 运用斜率优化类似操作进行优化 。
总的来说是一道不错的有思想的题目。
*/
#include
using namespace std;
#define ll long long
#define N 2000000
#define Max 1e18
#define Rate(i , k) (f[i] + M[k - i] + a[i])
ll L , R , last[N] , head[N] , to[N] , cnt = 0 , top = 0 , a[N] , M[N] , ans , n , f[N] , mx;
inline ll read()
{
ll x = 0 , f = 1ll; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') f = -1ll; ch = getchar();}
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
inline void ins(ll u ,ll v)
{
last[++cnt] = head[u] , head[u] = cnt , to[cnt] = v;
}
struct node
{
ll pre , x , sub;
}sta[N];
inline ll EFDA(ll x , ll y)
{
ll l = x + 1 , r = n , res = x + 1 , mid;
while(l <= r)
{
mid = (l + r) / 2;
if(f[x] + M[mid - x] + a[x] < f[y] + M[mid - y] + a[y]) l = mid + 1 , res = mid;
else r = mid - 1;
}
return res;
}
inline void dfs(ll x)
{
ll l = L , r = R , i , lst , Nowr;
for( ;sta[L].sub && Rate(sta[L].x , x) >= Rate(sta[sta[L].sub].x , x) ; L = sta[L].sub);
f[x] = (x - sta[L].x < mx) ? Rate(sta[L].x , x) : Max;
if(!head[x] && ans > f[x]) ans = f[x];
for( ; sta[R].pre && EFDA(sta[sta[R].pre].x , sta[R].x) >= EFDA(sta[R].x , x) ; R = sta[R].pre);
lst = sta[R].sub , Nowr = R;
sta[++top].pre = R , sta[top].x = x , sta[top].sub = 0 , sta[R].sub = top , R = top;
for(i = head[x] ; i ; i = last[i]) dfs(to[i]);
sta[Nowr].sub = lst , L = l , R = r;
}
int main()
{
// freopen("test.in" , "r" , stdin);
ll i , j , k , x , p;
n = read() , p = read();
for(i = 1 ; i <= n ; ++i) a[i] = read() , x = read() , ins(x , i);
for(i = 1 ; i <= n ; ++i)
{
M[i] = 1ll;
for(j = 1 ; j <= p ; ++j)
{
if((M[i] *= i) > Max) break;
}
if(M[i] > Max) break;
}
mx = (M[i] > Max ? i - 1 : i);
ans = Max;
sta[++top].pre = 0 , sta[top].x = 1 , sta[top].sub = 0 , L = R = 1;
for(i = head[1] ; i ; i = last[i]) dfs(to[i]);
printf("%lld\n" , ans);
return 0;
}