解:转移方程写出来,发现是斜率优化。因为在树上,考虑CDQ分治 + 点分治的方法...

每次找到重心,然后先递归解决上面的子树。然后把上面子树的凸包搞出来,下面每个点在凸包上二分找最优决策。

重心自己不参与上面子树的递归,单独给下面转移。

注意这个东西斜率可能有负数,不能简单乘到不等式另一边。

二分的写法要注意。

每个点的转移还有个深度限制,所以要按照深度限制把询问(待转移的点)排序,然后一边动态加凸包一边二分回答询问。

 #include <bits/stdc++.h>

 typedef long long LL;
const int N = , INF = 0x3f3f3f3f;
const double eps = 1e-; struct Edge {
int nex, v;
LL len;
}edge[N << ]; int tp = ; int e[N], _n, root, small, siz[N], deep[N], fa[N], stk[N], top2, stk2[N], SMALL, n;
LL p[N], q[N], lim[N], d[N], f[N];
bool del[N]; inline bool cmp_l(const int &a, const int &b) {
return lim[a] < lim[b];
} template <class T> inline void Min(T &a, const T &b) {
a > b ? a = b : ;
return;
} inline void add(int x, int y, LL z) {
tp++;
edge[tp].v = y;
edge[tp].len = z;
edge[tp].nex = e[x];
e[x] = tp;
return;
} void DFS_1(int x, int f) {
deep[x] = deep[f] + ;
fa[x] = f;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) continue;
d[y] = d[x] + edge[i].len;
DFS_1(y, x);
}
return;
} void getroot(int x, int f) {
//printf("getroot : %d %d \n", x, f);
int large = ;
siz[x] = ;
Min(SMALL, deep[x]);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(del[y] || y == f) continue;
getroot(y, x);
siz[x] += siz[y];
if(siz[y] > large) large = siz[y];
}
large = std::max(large, _n - siz[x]);
if(small > large) {
small = large;
root = x;
}
return;
} void DFS_2(int x, int f) {
stk2[++top2] = x;
//printf("DFS2 : %d \n", x);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(del[y] || y == f) continue;
DFS_2(y, x);
}
return;
} inline bool check(int a, int b, int c) {
return (long double)(f[b] - f[a]) / (d[b] - d[a]) + eps > (long double)(f[c] - f[b]) / (d[c] - d[b]);
} void DFS_3(int x, int f) {
siz[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(del[y] || y == f) continue;
DFS_3(y, x);
siz[x] += siz[y];
}
return;
} void DFS_4(int x, int father, int rt) {
if(x != rt && d[rt] >= lim[x]) {
Min(f[x], f[rt] - p[x] * d[rt]);
/*if(x == 5) {
printf("f %d = %lld rt = %d \n", x, f[x], rt);
}*/
}
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == father || del[y]) continue;
DFS_4(y, x, rt);
}
return;
} void CDQ(int x) { //printf("CDQ : %d _n = %d \n", x, _n); if(_n == ) {
f[x] += p[x] * d[x] + q[x];
del[x] = ;
//printf("1 : f [ %d ] = %lld \n", x, f[x]);
return;
} SMALL = small = INF;
getroot(x, );
int tempsmall = SMALL;
x = root;
DFS_3(x, );
del[x] = ;
///
if(del[fa[x]]) {
f[x] += p[x] * d[x] + q[x]; //printf("2 : f [ %d ] = %lld \n", x, f[x]); DFS_4(x, , x);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(del[y]) continue;
_n = siz[y];
CDQ(y);
}
return;
}
_n = siz[fa[x]];
CDQ(fa[x]); /**
while(top > 1 && check(stk[top - 1], stk[top], temp)) {
top--;
}
*/
top2 = ;
DFS_2(x, );
std::sort(stk2 + , stk2 + top2 + , cmp_l);
std::reverse(stk2 + , stk2 + top2 + );
int pos = fa[x], top = ;
//printf(" ----------------- x = %d fa[x] = %d \n", x, fa[x]);
/*printf("sort : ");
for(int i = 1; i <= top2; i++) {
printf("%d ", stk2[i]);
}
puts("");*/
for(int i = ; i <= top2; i++) {
int xx = stk2[i];
while(pos && deep[pos] >= tempsmall && d[pos] >= lim[xx]) {
/// insert p
while(top > && check(pos, stk[top], stk[top - ])) {
top--;
}
stk[++top] = pos;
//printf("insert pos = %d \n", pos);
pos = fa[pos];
}
if(!top) continue;
int l = , r = top;
//printf("l = %d r = top = %d \n", l, r);
while(l < r) {
int mid = (l + r) >> ;
//printf("mid = %d \n", mid);
if(l < mid && p[xx] > (long double)(f[stk[mid]] - f[stk[mid - ]]) / (d[stk[mid]] - d[stk[mid - ]])) {
r = mid - ;
}
else if(mid < r && p[xx] < (long double)(f[stk[mid + ]] - f[stk[mid]]) / (d[stk[mid +]] - d[stk[mid]])) {
//printf("-------------- %lld * %lld < %lld \n", p[xx], (d[stk[mid +1]] - d[stk[mid]]), (f[stk[mid + 1]] - f[stk[mid]]));
l = mid + ;
}
else {
r = mid;
break;
}
}
//printf("r = %d \n", r);
/// branch search OVER
//printf("Min %lld (%lld - %lld * %lld) \n", f[xx], f[stk[r]], p[xx], d[stk[r]]);
Min(f[xx], f[stk[r]] - p[xx] * d[stk[r]]);
//printf("%d -> %d f[%d] = %lld \n", stk[r], xx, xx, f[xx]);
} f[x] += p[x] * d[x] + q[x];
DFS_4(x, , x);
//printf("3 : f [ %d ] = %lld += %lld * %lld + %lld \n", x, f[x], p[x], d[x], q[x]); /// rest
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(del[y]) continue;
_n = siz[y];
CDQ(y);
}
return;
} int main() { freopen("in.in", "r", stdin);
//freopen("my.out", "w", stdout); memset(f, 0x3f, sizeof(f));
f[] = ;
int ttt; LL z;
scanf("%d%d", &n, &ttt);
for(int i = , x; i <= n; i++) {
scanf("%d%lld%lld%lld%lld", &x, &z, &p[i], &q[i], &lim[i]);
add(x, i, z); add(i, x, z);
}
/// input over
DFS_1(, );
for(int i = ; i <= n; i++) {
lim[i] = std::max(0ll, d[i] - lim[i]);
} //printf("OVER \n"); _n = n;
CDQ(); for(int i = ; i <= n; i++) {
printf("%lld\n", f[i]);
}
return ;
}

AC代码

最新文章

  1. SSM项目搭建(提供源码)
  2. Android 轮换控件
  3. 【noip 2016】 蚯蚓(earthworm)
  4. Iaas-cloudstack
  5. 《高性能MySQL》
  6. ios开发——实用技术篇Swift篇&amp;播放MP3
  7. 如何使用 Apache ab 以及 OneAPM 进行压力测试?
  8. CentOS 7.0 安装 python3.X 脚本
  9. LinkedList源码解析
  10. html基础标签-1-pre预格式标签
  11. JBPM6教程
  12. 关于csrss.exe和winlogon.exe进程多、占用CPU高的解决办法
  13. myeclipse复制项目
  14. Hibernate入门(五)
  15. 开源分享 Unity3d客户端与C#分布式服务端游戏框架
  16. Cleaner, more elegant, and wrong(msdn blog)
  17. iOS开发之UIWebView的常见一些用法
  18. 简单实现SSO
  19. Gym - 101982B Coprime Integers (莫比乌斯反演)
  20. 关于vue的增删改查操作

热门文章

  1. MyBaits全局配置文件的各项标签1
  2. java日志框架之logback(一)——logback工程简介
  3. Android——SMS接收发短信与运行权限
  4. python3 阿里云控制SLB权重
  5. maven 中的pom中的 dependencyManagement 和 dependencies
  6. C#中decimal,double和float的区别
  7. cefSharp 开发随笔
  8. jedis集群版应用
  9. JarvisOJ Basic 熟悉的声音
  10. 洛谷 P1102 A−B数对