bzoj3672
点分治+cdq分治
一看就是斜率优化,可惜在树上
有一个比较显然的方法是树链剖分凸包
但是复杂度较高
然而这道题可以用cdq分治
每次树分治的时候先处理朝向根的链的值
然后再更新儿子
#include <cstdio> #include <cstring> #include <algorithm> #include <string> using namespace std; typedef long long ll; const int N = 2e5 + 5; int n, top1, top2, top, cnt = 1, rt; struct edge { int nxt, to; ll w; } e[N << 1]; struct data { ll p, q, l; } a[N]; int h[N], vis[N], fa[N], sz[N], mx[N], st[N], st1[N], st2[N]; ll dep[N], dp[N]; void link(int u, int v, ll w) { e[++cnt].nxt = h[u]; h[u] = cnt; e[cnt].to = v; e[cnt].w = w; } bool cmp(int i, int j) { return dep[i] - a[i].l > dep[j] - a[j].l; } int getsize(int u, int last) { int ret = 1; for(int i = h[u]; i; i = e[i].nxt) { if(e[i].to == last || vis[e[i].to]) { continue; } ret += getsize(e[i].to, u); } return ret; } void getroot(int u, int last, int S) { sz[u] = 1; mx[u] = 0; for(int i = h[u]; i; i = e[i].nxt) { if(e[i].to == last || vis[e[i].to]) { continue; } getroot(e[i].to, u, S); sz[u] += sz[e[i].to]; mx[u] = max(mx[u], sz[e[i].to]); } mx[u] = max(mx[u], S - sz[u]); if(mx[u] < mx[rt]) { rt = u; } } void fill(int u, int last) { st2[++top2] = u; for(int i = h[u]; i; i = e[i].nxt) { if(e[i].to != last && !vis[e[i].to]) { fill(e[i].to, u); } } } double slope(int i, int j) { return (double)(dp[i] - dp[j]) / (dep[i] - dep[j]); } void update(int p) { if(!top) { return; } int l = 0, r = top, x = top; while(r - l > 1) { int mid = (l + r) >> 1; if(slope(st[mid], st[mid + 1]) < a[p].p) { r = x = mid; } else { l = mid; } } dp[p] = min(dp[p], dp[st[x]] + (dep[p] - dep[st[x]]) * a[p].p + a[p].q); } void divide(int u) { rt = 0; getroot(u, 0, getsize(u, 0)); vis[rt] = 1; int tmp = rt; if(u != rt) { divide(u); } rt = tmp; top1 = 0; top2 = 0; st1[++top1] = rt; for(int i = rt; i != u; i = fa[i]) { st1[++top1] = fa[i]; if(dep[rt] - dep[fa[i]] <= a[rt].l) { dp[rt] = min(dp[rt], dp[fa[i]] + (dep[rt] - dep[fa[i]]) * a[rt].p + a[rt].q); } } for(int i = h[rt]; i; i = e[i].nxt) { if(!vis[e[i].to]) { fill(e[i].to, 0); } } sort(st2 + 1, st2 + top2 + 1, cmp); top = 0; int j = 1; for(int i = 1; i <= top1; ++i) { int v = st1[i]; while(j <= top2 && dep[st2[j]] - a[st2[j]].l > dep[v]) { update(st2[j++]); } while(top > 1 && slope(st[top - 1], st[top]) < slope(st[top], v)) { --top; } st[++top] = v; } while(j <= top2) { update(st2[j++]); } for(int i = h[rt]; i; i = e[i].nxt) { if(!vis[e[i].to]) { divide(e[i].to); } } } int main() { // freopen("ticket.in", "r", stdin); // freopen("ticket.out", "w", stdout); // freopen("output.txt", "w", stdout); int laji; scanf("%d%d", &n, &laji); memset(dp, 0x3f3f, sizeof(dp)); dp[1] = 0; mx[0] = 0x3f3f3f3f; for(int i = 2; i <= n; ++i) { int f; ll d; scanf("%d%lld", &f, &d); fa[i] = f; scanf("%lld%lld%lld", &a[i].p, &a[i].q, &a[i].l); link(i, f, d); link(f, i, d); dep[i] = dep[f] + d; } divide(1); for(int i = 2; i <= n; ++i) { printf("%lld\n", dp[i]); } // fclose(stdin); // fclose(stdout); return 0; }