首页 > 其他分享 >[Bzoj 3252] 攻略 题解

[Bzoj 3252] 攻略 题解

时间:2024-01-26 09:02:35浏览次数:23  
标签:int 题解 3252 路径 son 叶子 add mx Bzoj

攻略

题面

\(n(\le2\cdot10^5)\) 个点的有根树,\(k(\le n)\) 次从根走到叶子,每个点有权值,求经过的点的权值和的最大值.(同一个点只能算一次)

Sol 1

我们设想一个叶子一个叶子加进去的过程。

如果有两个从某个点到叶子的路径,我们可以如图把他分成两条路径。

如图

那么他满足贪心,也就是每次选能产生最大贡献的叶子加入,最后的答案是最优的。

因为如果一个最优的叶子当前没有被加入,那你后面始终可以通过加入这个叶子得到更好的答案。

另外这个贪心感性理解上也是比较显然的。

由于同一个经过的点的权值不能被算多次,我们每加入一条从叶子一直往上的路径,就把路径上的点全部删除。

如图

注意删除这条路径还会给剩下的叶子的贡献造成影响。

那么我们维护这个贪心就行了:

  1. 找到最优的点
  2. 沿这个点往上爬,一边爬一边删除这个点,同时修改这个点的子树中的叶子的贡献

我们发现这个东西很多数据结构都可以维护,这里我们使用线段树:

  1. 找最优的点,也就是找贡献最大的点,相当于求全局最大值、最大值的编号
  2. 修改子树中所有叶子的贡献,也就是将子树中所有叶子的贡献减去这个点本身的权值,相当于区间减

总体来说,最多删 \(n\) 个点,每次删点区间修改 \(\mathcal O(\log n)\),\(k\) 次全局查询,直接 \(\mathcal O(1)\) 返回线段树根节点的数据即可,总复杂度 \(\mathcal O(n\log n)\).

上面已经讲的很清楚了,同时不建议看代码

  代码
#include <bits/stdc++.h>
using namespace std;
#define pb emplace_back
typedef long long ll;
constexpr int N = 2e5 + 10;
int n, k, m, fa[N], in[N], out[N], rev[N];
ll ans, a[N], b[N], c[N];
vector<int> G[N];
void dfs(int u) { b[u] += b[fa[u]]; if (G[u].empty()) return in[u] = out[u] = ++m, rev[m] = u, c[m] = b[u], void(); in[u] = m + 1; for (int v : G[u]) dfs(v); out[u] = m; }
// 预处理: 每个子树包含的叶子节点区间、每个叶子的贡献
struct Seg {
    ll mx[N << 2], add[N << 2]; int mxid[N << 2];
#define lc (u << 1)
#define rc ((u << 1) | 1)
#define mid ((l + r) >> 1)
    inline void push_up(int u) { mx[u] = max(mx[lc], mx[rc]), mxid[u] = mx[lc] > mx[rc] ? mxid[lc] : mxid[rc]; }
    inline void push_down(int u) { if (add[u]) mx[lc] += add[u], mx[rc] += add[u], add[lc] += add[u], add[rc] += add[u], add[u] = 0; }
    void build(int u, int l, int r) { add[u] = 0; if (l == r) return mx[u] = c[l], mxid[u] = l, void(); build(lc, l, mid), build(rc, mid + 1, r), push_up(u); }
    void upd(int u, int l, int r, int x, int y, ll v) { if (x <= l && r <= y) return mx[u] += v, add[u] += v, void(); push_down(u); if (x <= mid) upd(lc, l, mid, x, y, v); if (mid < y) upd(rc, mid + 1, r, x, y, v); push_up(u); }
} t;
// 区间加、全局查最大值及编号的线段树
int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    cin >> n >> k; for (int i = 1; i <= n; i++) cin >> a[i], b[i] = a[i]; for (int i = 1, u, v; i < n; i++) cin >> u >> v, G[u].pb(v), fa[v] = u;
    dfs(1); t.build(1, 1, m); while (k--) { ans += t.mx[1]; int u = rev[t.mxid[1]]; while (u) { for (int v : G[u]) fa[v] = 0; t.upd(1, 1, m, in[u], out[u], -a[u]), G[u].clear(), u = fa[u]; } }
    // k 次贪心
    cout << ans << "\n";
    return 0;
}

Sol 2

我们继承 Sol 1 的分路径思想和贪心思想。

我们发现贪心选择路径的顺序是固定的,同时如果更深一步思考,会发现这些叶子往上分得的路径从始至终都是固定的。

尝试预处理出这些路径,那么我们从大到小依次选出所含权值和最大的 \(k\) 个路径即可。

我们这样分配路径:

如图

我们像树链剖分一样,让一条从父节点延伸下来的路径往当前节点的一个儿子延伸,使这条路径上的点权之和最大;其余的儿子新开一条路径,成为这条路径的起始点。称这个儿子为当前节点的重儿子。

那么每个叶子节点恰好被一条路径包含;所有路径一共不重不漏恰好包含所有节点;包含根节点的路径的点权之和是最优的。

同时仔细想想就知道 Sol 1 中的一开始就固定的路径分配集合恰好就是我们分配出来的这样。

然后对每条路径的权值和排序,从大到小选 \(k\) 个加入答案即可。

预处理是 \(\mathcal O(n)\) 的,总复杂度 \(\mathcal O(n\log n)\),瓶颈在于排序。

代码针对可读性做了优化。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
constexpr int N = 2e5 + 10;
int n, k, tot, a[N], son[N];
ll ans, len[N], s[N];
vector<int> G[N];
void dfs(int u, int f) {
    for (int v : G[u]) dfs(v, u), son[u] = len[v] > len[son[u]] ? v : son[u];
    len[u] = len[son[u]] + a[u];
    for (int v : G[u])
        if (v != son[u]) s[tot++] = -len[v];
}
int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i) scanf("%d", a + i);
    for (int i = 1, u, v; i < n; ++i) {
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
    }
    dfs(1, 0); ans = len[1];
    sort(s, s + tot);
    for (int i = 0; i < min(k - 1, tot); ++i) ans -= s[i];
    printf("%lld\n", ans);
    return 0;
}

Sol 3

有一个显然的树形 dp:

\(f_{u,i}\) 表示 \(u\) 子树走到叶子 \(i\) 次的权值和最大值.

\(f_{u,i}=\max f_{u,j}+f_{v,i-j},j\in[0,\min(son(u),i)]\)

其中 \(v\) 为 \(u\) 儿子,\(son(u)\) 表示 \(u\) 子树内的叶子节点个数。

因为叶子节点个数不超过子树大小,\(k\) 与 \(n\) 同阶,所以复杂度比 \(\mathcal O(n^2)\) 小,但是最大是 \(\mathcal O(n^2)\),比如菊花图。

发现这是 \((+,\max)\) 形式的卷积,同时 \(f_{u,i}\) 随 \(i\) 单调递增,可以闵可夫斯基和优化。

然后就没了。

代码还没写。

标签:int,题解,3252,路径,son,叶子,add,mx,Bzoj
From: https://www.cnblogs.com/laijinyi/p/17988557/bzoj-3252

相关文章

  • P4159 [SCOI2009] 迷路 题解
    P4159[SCOI2009]迷路搬运工题目链接首先我们先考虑这道题的弱化版如何处理。假如所有的边权都是零和一。这时他们的边权可以看做这两个点走一步到达之间的方案数。而对于走t步,我们可以推出下列式子,\(f_{i,j}\)表示从节点\(i\)到节点\(j\)的方案数。\[f_{i,j}=\su......
  • # python3 安装Crypto包 出现No module named ‘Crypto‘和No module named ‘Crypto.
    python3安装Crypto包出现Nomodulenamed‘Crypto‘和Nomodulenamed‘Crypto.Util‘问题解决方法1.改成安装pycryptodome然而在python36中无法报错:error:MicrosoftVisualC++14.0orgreaterisrequired"2.改用Anaconda安装指定版本的pycryptodomepipins......
  • 2024年1月Java项目开发指南12:前后端分离项目跨域问题解决
    创建config文件夹,创建WebConfig文件代码如下(可以直接抄)packagecc.xrilang.serversystem.config;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.CorsRegistry;importorg.springframework.web.se......
  • CF145E Lucky Queries 题解
    题目链接:CF或者洛谷前置知识点:序列操作本文关键词约定俗称:因为频繁敲最长不下降子序列\(LNCS\)和最长不上升子序列\(LNIS\)太麻烦了,下文将\(000011111\)这种最长不降子序列用\(LIS\)描述,\(1111100000\)这种最长不升子序列用\(LDS\)描述。这里面只有\(4\)和\(7......
  • 魔法少女LJJ 题解
    魔法少女LJJ题解这题纯属就是迷惑题。。为什么这么说?注意数据范围:对100%的数据\(0\leqm\leq400000\),\(c\leq7\)。\(c\leq7\)!!这意味着根本没有删除操作。就连样例也是错的。Solution这题的各种操作,用并查集+线段树合并完成。如果你是被题目数据范围晃飞的,建议......
  • loj 6095 花神的嘲讽计划 题解
    题目哈希记录每个\(k\)长度的串,询问的时候可以拿主席树或二分,这里说下二分。将\(n-k+1\)个串从小到大排序,以哈希值为第一关键字,序号为第二关键字。每次询问直接查找大于等于当前哈希值的位置即可,找到之后判断一下合不合法即可。具体看代码:#include<bits/stdc++.h>typede......
  • P8659 [蓝桥杯 2017 国 A] 数组操作 题解
    题目链接:洛谷或者蓝桥杯或者C语言中文网几个OJ的AC记录:忘了哪个OJ的:洛谷:C语言中文网:蓝桥杯:emmmmmmm,好像每个OJ给的时限和空间还不一样,蓝桥杯官方还给了$3s$和$2G$,C语言中文网机子比较老可能,挺卡常的,开了个究极快读和指令集就过去了,也可以自己调下重构常数,偷懒......
  • P3355 骑士共存问题题解
    题目链接:P3355骑士共存问题-洛谷|计算机科学教育新生态(luogu.com.cn)题解:棋盘问题考虑黑白染色成为二分图后做。观察马的性质,可知一个点只能到一个异色点,所以,构造方案可以先将所有同色点放上马,再考虑有那些异色点不可以放置。方法一:网络流,时间复杂度为O(|E|min(|E|0.5......
  • P7900 [COCI2006-2007#2] SJECIŠTA_题解
    [COCI2006-2007#2]SJECIŠTA_题解rt我们来看一下题目描述考虑一个有$n$个顶点的凸多边形,且这个多边形没有任何三个(或以上)的对角线交于一点。这句话什么意思?当顶点为$n$的图形为正多边形时便有可能出现一个点是有三条线相交而构成的如图如图情况就有三个......
  • P9779_[HUSTFC 2023] 不定项选择题_题解
    rt题目有一道共n个选项的不定项选择题,它的答案至少包含一个选项,由于题目与选项的内容晦涩难懂,你打算通过尝试每一种可能的答案来通过这道题。初始时所有选项都没有被勾选,你可以执行任意次下述操作:勾选一个当前未被勾选的选项。取消勾选一个当前已被勾选的选项。当你......