# BZOJ3672: [Noi2014]购票【CDQ分治】【点分治】【斜率优化DP】

7 3
1 2 20 0 3
1 5 10 100 5
2 4 10 10 10
2 9 1 100 10
3 5 20 100 10
4 4 20 0 10

40
150
0
149
300
150

n=2×10^5

## 思路

#include<bits/stdc++.h>

using namespace std;

typedef long double ld;
typedef long long ll;

ll res = 0, w = 1; char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') c = getchar(), w = -1;
while (isdigit(c)) res = (res << 1) + (res << 3) + c - '0', c = getchar();
return w * res;
}

const ll INF_of_ll = 1e18;
const ll N = 2e5 + 10;

struct Node {
ll id, val;
Node() {}
Node(ll id, ll val): id(id), val(val) {}
} rque[N];

bool operator < (const Node &a, const Node &b) {
return a.val > b.val;
}

struct Vector {
ll x, y;
Vector() {}
Vector(ll x, ll y): x(x), y(y) {}
} lque[N];

Vector operator - (const Vector &a, const Vector &b) {
return Vector(a.x - b.x, a.y - b.y);
}

ld operator * (const Vector &a, const Vector &b) {
return (ld) a.x * b.y - (ld) a.y * b.x;
}

struct Edge {
ll v, w, nxt;
} E[N << 1];

ll topl, topr;
ll n, prt[N], p[N], q[N], limit[N], dp[N];
ll siz[N], dis[N], F[N], vis[N], siz_all;

void addedge(ll u, ll v, ll w) {
E[++tot] = (Edge) {v, w, head[u]};
}

void getsiz(ll u) {
siz[u] = 1;
for (ll i = head[u]; i; i = E[i].nxt) {
ll v = E[i].v;
if (vis[v]) continue;
dis[v] = dis[u] + E[i].w;
getsiz(v);
siz[u] += siz[v];
}
}

void getrt(ll u, ll &rt) {
F[u] = siz_all - siz[u];
for (ll i = head[u]; i; i = E[i].nxt) {
ll v = E[i].v;
if (vis[v]) continue;
getrt(v, rt);
F[u] = max(F[u], siz[v]);
}
if (F[u] < F[rt] && siz[u] > 1) rt = u;
}

void dfs(ll u) {
rque[++topr] = (Node) {u, dis[u] - limit[u]};
for (ll i = head[u]; i; i = E[i].nxt)
if (!vis[E[i].v]) dfs(E[i].v);
}

ll calc(ll v, Vector u) {
return u.y + (dis[v] - u.x) * p[v] + q[v];
}

void solve(ll u, ll cursiz) {
if (cursiz == 1) return;
ll rt = 0;
getsiz(u);
F[rt] = siz_all = cursiz;
getrt(u, rt);
for (ll i = head[rt]; i; i = E[i].nxt)
vis[E[i].v] = 1;
solve(u, cursiz - siz[rt] + 1);
topl = topr = 0;
for (ll i = head[rt]; i; i = E[i].nxt)
dfs(E[i].v);
sort(rque + 1, rque + topr + 1);
ll cur = rt;
lque[0] = Vector(dis[rt] + 1, INF_of_ll);
for (ll i = 1; i <= topr; i++) {
while (cur != prt[u] && dis[cur] >= rque[i].val) {
Vector now(dis[cur], dp[cur]);
while (topl > 1 && (lque[topl] - lque[topl - 1]) * (now - lque[topl - 1]) > 0.0) topl--;
lque[++topl] = now;
cur = prt[cur];
}
if (topl) {
ll l = 1, r = topl, res = 1, now = rque[i].id;
while (l <= r) {
ll mid = (l + r) >> 1;
if (calc(now, lque[mid]) <= calc(now, lque[mid - 1])) res = mid, l = mid + 1;
else r = mid - 1;
}
dp[now] = min(dp[now], calc(now, lque[res]));
}
}
for (ll i = head[rt]; i; i = E[i].nxt)
solve(E[i].v, siz[E[i].v]);
}

int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
for (ll i = 2; i <= n; i++) {
}