# dp 可并堆 uoj205【APIO2016】Fireworks

http://uoj.ac/problem/205

$$f$$值形成了一个下凸包

$$x$$的斜率分别为$$-1, 0, 1$$

$$f[rt]$$的凸包与$$y$$轴交点已知
$$\sum$$边权

#include<bits/stdc++.h>
#define int long long
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
x = 0;char c = getchar(); bool f = 0;
for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
for(int i = 1; i <= n; i ++)
cout << a[i] << " ";
puts("");
}
const int N = 6e5 + 233;
int n, m, fa[N], w[N], sz[N], ans = 0;
int key[N], fix[N], sa = 0, L[N], R[N], rt[N];
inline int nw(int val) {
++ sa; L[sa] = R[sa] = 0;
key[sa] = val;
fix[sa] = rand();
return sa;
}

inline int make(int x, int y) {
if(!x || !y) return x | y;
if(key[x] < key[y]) swap(x, y);
if(fix[x] < fix[y])
R[x] = make(R[x], y);
else
L[x] = make(L[x], y);
return x;
}

inline void pop(int x) {
rt[x] = make(L[rt[x]], R[rt[x]]);
}

inline void dfs(int x) {
if(!x) return ;
cout << key[x] << " " << x << "\n";
dfs(L[x]); dfs(R[x]);
}

main(void) {
srand(20021214);
int all = n + m;
for(int i = 2; i <= all; i ++) {
ans += w[i];
sz[fa[i]] ++;
}
for(int i = all; i >= 2; i --) {
int l = 0, r = 0;
if(sz[i]) {
while(-- sz[i]) pop(i);
r = key[rt[i]]; pop(i);
l = key[rt[i]]; pop(i);
}
l = nw(l + w[i]);
r = nw(r + w[i]);
rt[i] = make(rt[i], make(l, r));
rt[fa[i]] = make(rt[fa[i]], rt[i]);
}
while(sz[1] --) pop(1);
while(rt[1]) {
ans -= key[rt[1]];
pop(1);
}
cout << ans << "\n";
}

dp 可并堆 uoj205【APIO2016】Fireworks

(0)
(0)

0条