2020.9.2 校训
第一次尝试主用vim写代码,感觉还不错
J
首先看到这题的第一眼我的反应是先来一个一个
O
(
n
log
n
)
O(n \log{n})
O(nlogn)的排序(数据范围给的也很符合)。排序之后,可以根据“区间不交叉”这一性质建树,每个节点的父节点完全包含其所有儿子(需要手动添加一个在[-1,1e6]跨度上权值为0的节点作为根节点)。
粗看可以用O
(
n
2
)
(n^2)
(n2)的DP来做,大概就是dp[i][j]表示“第i大的节点为根的子树上,最多允许点亮j条边”子问题的解。然而根据题解中提到的闵可夫斯基定理,可以利用f[i][j]-f[i][j-1]不增的性质进行优化,最终复杂度为
O
(
n
log
n
)
O(n \log n)
O(nlogn)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, s, h[250001];
struct edge
{
int id;
int s, e, fa;
ll v;
vector<int> des;
void init(int idx, int S, int E, int V)
{
id = idx;
s = S;
e = E;
v = V;
fa = -1;
}
} a[250001];
priority_queue<ll> q[250001];
bool cmp(const edge &x, const edge &y)
{
if (x.s == y.s)
return (x.e > y.e);
return x.s < y.s;
}
vector<ll> t;
void visit(int idx)
{
int maxi = 0, maxs = 0;
for (auto j : a[idx].des)
{
visit(j);
if (q[h[j]].size() > maxs)
{
maxs = q[h[j]].size();
maxi = j;
}
}
h[idx] = h[maxi];
for (auto j : a[idx].des)
{
if (j == maxi)
continue;
for (t.clear(); !q[h[j]].empty();)
{
t.push_back(q[h[idx]].top() + q[h[j]].top());
q[h[idx]].pop();
q[h[j]].pop();
}
for (auto tmp : t)
q[h[idx]].push(tmp);
}
if (!h[idx])
h[idx] = ++s;
if (idx)
q[h[idx]].push(a[idx].v);
}
int main()
{
// freopen("jin", "r", stdin);
scanf("%d", &n);
a[0].init(0, -1, 1e6 + 2, 0);
for (int i = 1, s, e, v; i <= n; ++i)
{
scanf("%d%d%d", &s, &e, &v);
a[i].init(i, s, e - 1, v);
}
sort(a, a + n + 1, cmp);
int fa = 0;
for (int i = 1; i <= n; ++i)
{
a[i].id = i;
while (a[i].s > a[fa].e && fa != 0)
{
fa = a[fa].fa;
}
a[fa].des.push_back(i);
a[i].fa = fa;
fa = i;
}
visit(0);
ll ans = 0;
for (int i = 1; i <= n; ++i)
{
if (!q[h[0]].empty())
{
ans += q[h[0]].top();
q[h[0]].pop();
}
printf("%lld ", ans);
}
puts("");
return 0;
}