BZOJ 2286

传说中的虚树经典题。

放上我觉得讲的很好的Luogu置顶题解。       传送门

首先考虑一个暴力的$dp$,设$f_x$表示切断$x$的子树中的所有特殊点且保留$x$的最小代价和,$mn_x$表示$x$到根的路径上最小的一条边的权值。

边界:搜一遍预处理$mn$,对于所有的特殊点$x$, $f_x = mn_x$,其他的点$y$,$f_y = 0$。

转移也比较显然$f_x = \sum_{y} min(mn_y, f_y)$   $y \in son(x)$。

这样子$n^2$的做法就拿到了40分。

我们在$dp$的时候发现其实一次要用的点很少,最多就是所有的特殊点,$1$,还有一些特殊点的$lca$,那么我们可以直接把这些需要的点保留下来重新构造一颗新的树来$dp$,这样子会快很多。

好像这个东西就叫虚树吧。

对于一棵树,我们只要知道了它的欧拉序就可以知道这棵树到底是长什么样的,发现构造出来的这颗新的树上所有点的相对欧拉序都没有变化,而且使用欧拉序还有一个好处,那就是在插入$lca$的时候只要先按照欧拉序排一波序然后按顺序插入就好了,感觉这比很多网上的用栈维护这个$lca$的方法要好很多。

按照所有点的欧拉序排序后模拟系统栈$dp$即可。

时间复杂度似乎是$O(nlogn)$,并不会算。

另外注意每次在弹栈的时候初始化一下就好了,我一开始用$memset$T了。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;const int N = 2.5e5 + 5;
const int Lg = 20;
const ll inf = 1LL << 60;int n, qn, tot = 0, head[N], top = 0, sta[N << 2], a[N << 2];
int fa[N][Lg], dep[N], dfsc = 0, in[N], out[N];
ll mn[N], f[N];
bool vis[N];struct Edge {int to, nxt;ll val;
} e[N << 1];inline void add(int from, int to, ll val) {e[++tot].to = to;e[tot].val = val;e[tot].nxt = head[from];head[from] = tot;
}template <typename T>
inline void read(T &X) {X = 0; char ch = 0; T op = 1;for(; ch > '9' || ch < '0'; ch = getchar())if(ch == '-') op = -1;for(; ch >= '0' && ch <= '9'; ch = getchar())X = (X << 3) + (X << 1) + ch - 48;X *= op;
}bool cmp(int x, int y) {int dfx = x > 0 ? in[x] : out[-x];int dfy = y > 0 ? in[y] : out[-y];return dfx < dfy;
}inline ll min(ll x, ll y) {return x > y ? y : x;
}void dfs(int x, int fat, int depth, ll nowMn) {fa[x][0] = fat, dep[x] = depth, mn[x] = nowMn;in[x] = ++dfsc;for(int i = 1; i <= 18; i++)fa[x][i] = fa[fa[x][i - 1]][i - 1];for(int i = head[x]; i; i = e[i].nxt) {int y = e[i].to;if(y == fat) continue;dfs(y, x, depth + 1, min(nowMn, e[i].val));}out[x] = ++dfsc;
}inline void swap(int &x, int &y) {int t = x; x = y; y = t;
}inline int getLca(int x, int y) {if(dep[x] < dep[y]) swap(x, y);for(int i = 18; i >= 0; i--)if(dep[fa[x][i]] >= dep[y])x = fa[x][i];if(x == y) return x;for(int i = 18; i >= 0; i--)if(fa[x][i] != fa[y][i])x = fa[x][i], y = fa[y][i];return fa[x][0];
}void solve() {int K, cnt; read(K);for(int i = 1; i <= K; i++) {read(a[i]);vis[a[i]] = 1, f[a[i]] = mn[a[i]];}cnt = K;sort(a + 1, a + 1 + cnt, cmp);for(int i = 1; i < cnt; i++) {int now = getLca(a[i], a[i + 1]);if(!vis[now]) {vis[now] = 1;a[++cnt] = now;}}for(int cur = cnt, i = 1; i <= cur; i++)a[++cnt] = -a[i];if(!vis[1]) a[++cnt] = 1, a[++cnt] = -1;sort(a + 1, a + 1 + cnt, cmp);top = 0;for(int i = 1; i <= cnt; i++) {if(a[i] > 0) sta[++top] = a[i];else {int x = sta[top--];if(x == 1) printf("%lld\n", f[x]);else {int y = sta[top];f[y] += min(mn[x], f[x]);            }f[x] = 0LL, vis[x] = 0;}}
}int main() {read(n);for(int x, y, i = 1; i < n; i++) {read(x), read(y);ll v; read(v);add(x, y, v), add(y, x, v);}    dfs(1, 0, 1, inf);for(read(qn); qn--; ) solve();return 0;
}

View Code

转载于:https://www.cnblogs.com/CzxingcHen/p/9698976.html

Luogu 2495 [SDOI2011]消耗战相关推荐

  1. 「Luogu2495」 [SDOI2011]消耗战 虚树

    Luogu P2495 [SDOI2011]消耗战 problem Solution 苦思冥想稍作思考之后可以得到一个树形DP的方法: 令\(w(u,v)\)表示u,v之间的边的权值,\(f[u]\) ...

  2. [SDOI2011]消耗战

    [SDOI2011]消耗战 题意: 给出n个点的一棵带有边权的树,以及q个询问.每次询问给出k个点,询问这使得这k个点与1点不连通所需切断的边的边权和最小是多少. 题解: 树型dp+虚树 dp[x]: ...

  3. BZOJ2286: [Sdoi2011]消耗战(虚树)

    BZOJ2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MB Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成, ...

  4. [Luogu 2486] SDOI2011 染色

    [Luogu 2486] SDOI2011 染色 树剖水题,线段树维护. 详细题解不写了. 我只想说我写的线段树又变漂亮了qwq #include <algorithm> #include ...

  5. 虚树+树型DP SDOI2011消耗战

    <虚树+树型DP> SDOI2011消耗战 #include <iostream> #include <cstdio> #include <cstring&g ...

  6. P2495 [SDOI2011]消耗战

    P2495 [SDOI2011]消耗战 虚树+dpdpdp. 每次在整个图上跑dpdpdp时间肯定不够,所以考虑只对查询点和其lcalcalca进行建图. 此题的dpdpdp转移有两种方式:一种是直接 ...

  7. P2495 [SDOI2011]消耗战(树形dp+虚树)

    P2495 [SDOI2011]消耗战 树形dp 状态表示:fuf_ufu​表示以uuu为根的子树中,uuu节点与子树中的关键的"隔开"所需要的最小代价 状态转移: 考虑uuu的一 ...

  8. 洛谷P2495 [SDOI2011]消耗战(虚树dp)

    P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ...

  9. BZOJ 2281 Luogu P2490 [SDOI2011]黑白棋 (博弈论、DP计数)

    怎么SDOI2011和SDOI2019的两道题这么像啊..(虽然并不完全一样) 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?i ...

最新文章

  1. 在吗?认识一下JWT(JSON Web Token) ?
  2. Spring基础专题——第十一章(高级注解编程完结)
  3. OC与Swift封装网络工具类
  4. python编程入门电子书下载-最经典的25本Python编程开发电子书(附下载地址)!...
  5. 通过xshell在linux上安装mysql5.7(终极版)
  6. Java多线程——同步问题
  7. python 中self
  8. java swt 双屏_SWT(JFace)体验之打开多个Form
  9. Jpeg图像转yuv 16倍数问题(第一季)
  10. 关于PCB板设计中电阻电容等封装的选择
  11. 相机参数标定+透视变换
  12. CM添加kafka服务
  13. win10合并硬盘合区(win10怎样合并硬盘的两个分区)
  14. 何为项目管理中的S曲线?
  15. STM32DAC输出遇到的问题
  16. 实现给页面长截图,带滚动条的部分也截取
  17. 免费资源丨如何快速发表论文?八种实验套路及论文技巧告诉你
  18. iOS 读书笔记-单元测试XCTest
  19. 如何使用DEV-C++(超详细)
  20. 鸿蒙系统中的 WebView 加载H5页面出现net::ERR_CLEARTEXT_NOT_PERMITTED的解决方法

热门文章

  1. 一个男人关心的东西决定了他的层次
  2. TE、TM、TEM模式的区别
  3. aix kill java_AIX环境Java进程cpu瓶颈分析(转)
  4. SpringBoot_整合SpringSecurity(前后端分离版)
  5. 什么是移动终端应用开发平台?
  6. Task01:数据载入及初步观察
  7. vc++拾遗(7)-框架、视图、文档
  8. jmeter-阶梯式性能指标监听
  9. 阿里云盘 PC端 v2.1.3
  10. BP神经网络实现风功率预测