题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=3252

题解

有一个非常显然的贪心思路:每次选择目前走到那儿能够获得的新权值最大的点。

证明的话,因为走过的点不再计入贡献,所以不这样走不可能有更优的。

考虑怎么维护每个点能够获得的新点权的最大值。

因为每个点只能做一次贡献,所以走过去以后对整个子树的作用都消失了,可以使用线段树区间修改。

还是因为每个点只能做一次贡献,所以每一次修改可以暴力跳父节点,直到跳到已经做过贡献的点为止。


时间复杂度 \(O((n+m)\log n)\)。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
} const int N = 200000 + 7; #define lc o << 1
#define rc o << 1 | 1 int n, k, dfc;
int a[N], f[N], dfn[N], pre[N], siz[N], vis[N];
ll dis[N]; struct Edge { int to, ne; } g[N << 1]; int head[N], tot;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); } struct Node { ll add, max; int pos; } t[N << 2];
inline void pushup(int o) {
t[o].max = 0;
if (smax(t[o].max, t[lc].max)) t[o].pos = t[lc].pos;
if (smax(t[o].max, t[rc].max)) t[o].pos = t[rc].pos;
t[o].max += t[o].add;
// dbg("o = %d, t[o].max = %lld, t[o].pos = %d\n", o, t[o].max, t[o].pos);
}
inline void build(int o, int L, int R) {
if (L == R) return t[o].max = dis[pre[L]], t[o].pos = pre[L], (void)0;
int M = (L + R) >> 1;
build(lc, L, M), build(rc, M + 1, R);
pushup(o);
}
inline void qadd(int o, int L, int R, int l, int r, int k) {
if (l <= L && R <= r) return t[o].max += k, t[o].add += k, (void)0;
int M = (L + R) >> 1;
if (l <= M) qadd(lc, L, M, l, r, k);
if (r > M) qadd(rc, M + 1, R, l, r, k);
pushup(o);
} inline void dfs(int x, int fa = 0) {
dfn[x] = ++dfc, pre[dfc] = x, siz[x] = 1, dis[x] = dis[fa] + a[x], f[x] = fa;
for fec(i, x, y) if (y != fa) dfs(y, x), siz[x] += siz[y];
} inline void work() {
dfs(1), build(1, 1, n);
ll ans = 0;
while (k--) {
int p = t[1].pos;
ans += t[1].max;
// dbg("p = %d, val = %lld\n", p, t[1].max + t[1].add);
while (p && !vis[p]) qadd(1, 1, n, dfn[p], dfn[p] + siz[p] - 1, -a[p]), vis[p] = 1, p = f[p];
// dbg("end: p = %d\n", p);
}
printf("%lld\n", ans);
} inline void init() {
read(n), read(k);
for (int i = 1; i <= n; ++i) read(a[i]);
int x, y;
for (int i = 1; i < n; ++i) read(x), read(y), adde(x, y);
} int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}

bzoj3252 攻略 贪心+dfs序+线段树的更多相关文章

  1. 【bzoj3252】攻略 贪心+DFS序+线段树

    题目描述 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某 ...

  2. [Bzoj3252]攻略(dfs序+线段树)

    Description 题目链接 Solution 可以想到,每次肯定是拿最大价值为最优 考虑改变树上一个点的值,只会影响它的子树,也就是dfs序上的一个区间, 于是可以以dfs序建线段树,这样就变成 ...

  3. BZOJ 3252题解(贪心+dfs序+线段树)

    题面 传送门 分析 此题做法很多,树形DP,DFS序+线段树,树链剖分都可以做 这里给出DFS序+线段树的代码 我们用线段树维护到根节点路径上节点权值之和的最大值,以及取到最大值的节点编号x 每次从根 ...

  4. BZOJ3252 攻略(贪心+dfs序+线段树)

    考虑贪心,每次选价值最大的链.选完之后对于链上点dfs序暴力修改子树.因为每个点最多被选一次,复杂度非常正确. #include<iostream> #include<cstdio& ...

  5. 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

    3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] D ...

  6. 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

    题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...

  7. Codeforces Round #442 (Div. 2)A,B,C,D,E(STL,dp,贪心,bfs,dfs序+线段树)

    A. Alex and broken contest time limit per test 2 seconds memory limit per test 256 megabytes input s ...

  8. Educational Codeforces Round 6 E dfs序+线段树

    题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...

  9. Codeforces 343D Water Tree(DFS序 + 线段树)

    题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...

随机推荐

  1. 2019年CCPC网络赛 HDU 6703 array【权值线段树】

    题目大意:给出一个n个元素的数组A,A中所有元素都是不重复的[1,n].有两种操作:1.将pos位置的元素+1e72.查询不属于[1,r]中的最小的>=k的值.强制在线. 题解因为数组中的值唯一 ...

  2. uva live 7639 Extreme XOR Sum (暴力+二项式)

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...

  3. ASP 数据库分页

    <%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%> <% Response.buffer=false %> ...

  4. leetcode 39. 组合总和(python)

    给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限制重复被选 ...

  5. 当在浏览器中输入一个url后回车,后台发生了什么?比如输入url后,你看到了百度的首页,那么这一切是如何发生的呢?

    简单来书有以下步骤: 查找域名对应的IP地址.这一步会依次查找浏览器缓存,系统缓存,路由器缓存,ISPDNS缓存,13台根域名服务器. 向IP对应的服务器发送请求. 服务器响应请求,发回网页内容. 浏 ...

  6. 安全测试工具之AppScan(Application)

    AppScan是一款Web应用安全测试工具,也是唯一一个在所有级别应用上提供安全纠正任务的工具.AppScan扫描Web应用的基础架构,进行安全漏洞测试并提供可行的报告和建议.AppScan的扫描能力 ...

  7. K近邻实战手写数字识别

    1.导包 import numpy as np import operator from os import listdir from sklearn.neighbors import KNeighb ...

  8. pandas 入门(3)

    from pandas import Series, DataFrame, Index import numpy as np # 层次化索引 对数据重塑和分组操作很有用 data = Series(n ...

  9. python+selenium的frame表单切换

    switch_to.frame()                               切换frame switch_to.default_content()                切 ...

  10. Struts2异常:HTTP Status 404 - /Struts2/book/addBook.action

    HTTP Status 404 - /Struts2/book/addBook.action 如果在Struts2的框架中访问路径出现了这个错误,可能存在的原因有如下的两个: 1. 路径写错,也就是a ...