题目大意

给你\(k\)个点,让这一些点和一号节点断开,删去某一些边,求最小的删去边权之和。

做题的心路历程

做了\(HG\)昨天的模拟赛,深深感觉到了窝的菜,所以为了\(A\)掉T1这一道毒瘤,窝就来学习一下虚树。
学到一半,感觉虚树的原理还是比较简单的,就是把需要求的点建一棵和原来的树长得十分相似的一棵树,然后在这个树上做\(DP\)。
但是,我写到完了,就一直T。也不知道为什么。
然后删掉了所有的memset就瞬间跑了出来。原来是因为自己太怂了。。。

题解

首先如果考虑最简单的树形\(DP\)。
\(f[i]\)表示以\(i\)为根节点的答案。
那么我们需要预处理出每一个节点到根节点\(1\)的最小边权设为\(me[i]\),那么就得到了\(f[i]=\sum \ min(f[i],me[i])\)
但是发现,如果每一个询问都做一遍树形\(DP\),那么一定是要炸的。
那么就对于我们需要询问的节点建立一个树,然后在这个树上跑DP。

代码

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define N 550005
#define ms(a, b) memset(a, b, sizeof(a))
#define ll long long
#define BIT 19
using namespace std;
template <typename T> void read(T &x) {
    x = 0; T fl = 1; char ch = 0;
    for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') fl = -1;
    for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
    x *= fl;
}
struct edge { int to, nt, w; } E[N << 1];
vector<int> G[N];
int H[N], dfn[N], ispoint[N], f[N][BIT + 5], dep[N], p[N], stk[N];
ll me[N];
int cnt, __dfn, n, Q, k, top;
void add_edge(int u, int v, int w) { E[++ cnt] = (edge){v, H[u], w}; H[u] = cnt; }
bool cmp(int A, int B) { return dfn[A] < dfn[B]; }
void dfs1(int u, int fa) {
    f[u][0] = fa; dfn[u] = ++ __dfn; dep[u] = dep[fa] + 1;
    for (int i = 1; i <= BIT; i ++) f[u][i] = f[f[u][i - 1]][i - 1];
    for (int e = H[u]; e; e = E[e].nt) { int v = E[e].to; if (v == fa) continue; me[v] = E[e].w; if (u != 1 && me[u] < me[v]) me[v] = me[u]; dfs1(v, u);  }
}
int lca(int u, int v) {
    if (dep[u] < dep[v]) swap(u, v);
    for (int i = BIT; ~i; i --)
        if (dep[f[u][i]] >= dep[v]) u = f[u][i];
    if (u == v) return u;
    for (int i = BIT; ~i; i --)
        if (f[u][i] != f[v][i]) u = f[u][i], v = f[v][i];
    return f[u][0];
}
void insert(int u) {
    if (top == 1) { stk[++ top] = u; return; }
    int Lca = lca(u, stk[top]);
    if (Lca == stk[top]) { stk[++ top] = u; return; }
    while (top > 1 && dfn[Lca] <= dfn[stk[top - 1]]) G[stk[top - 1]].push_back(stk[top]), -- top;
    if (Lca != stk[top]) G[Lca].push_back(stk[top]), stk[top] = Lca;
    stk[++ top] = u;
}
ll DP(int u) {
    ll res = 0;
    for (int i = 0; i < (int) G[u].size(); i ++) {
        int v = G[u][i]; res += min(me[v], DP(v));
    }
    G[u].clear();
    if (ispoint[u]) return me[u]; else return res;
}
int main() {
    read(n);
    for (int i = 1, u, v, w; i < n; i ++) { read(u); read(v); read(w); add_edge(u, v, w); add_edge(v, u, w);  }
    __dfn = 0; dfs1(1, 0);
    read(Q);
    while (Q --) {
        read(k);  for (int i = 1; i <= k; i ++) read(p[i]), ispoint[p[i]] = 1;
        sort(p + 1, p + 1 + k, cmp);  top = 0; stk[++ top] = 1;
        for (int i = 1; i <= k; i ++) insert(p[i]);
        while (top > 0) { G[stk[top - 1]].push_back(stk[top]); top --; }
        printf("%lld\n", DP(1));
        for (int i = 1; i <= k; i ++) G[p[i]].clear(), ispoint[p[i]] = 0; G[0].clear();
    }
    return 0;
}

「洛谷2495」「BZOJ3052」「SDOI2001」消耗战【虚树+树形动态规划】的更多相关文章

  1. 「区间DP」「洛谷P1043」数字游戏

    「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...

  2. 「 洛谷 」P2768 珍珠项链

    珍珠项链 题目限制 内存限制:125.00MB 时间限制:1.00s 标准输入输出 题目知识点 动态规划 \(dp\) 矩阵 矩阵乘法 矩阵加速 矩阵快速幂 题目来源 「 洛谷 」P2768 珍珠项链 ...

  3. 「 洛谷 」P4539 [SCOI2006]zh_tree

    小兔的话 推荐 小兔的CSDN [SCOI2006]zh_tree 题目限制 内存限制:250.00MB 时间限制:1.00s 标准输入输出 题目知识点 思维 动态规划 \(dp\) 区间\(dp\) ...

  4. 「 洛谷 」P2151 [SDOI2009]HH去散步

    小兔的话 欢迎大家在评论区留言哦~ HH去散步 题目限制 内存限制:125.00MB 时间限制:1.00s 标准输入 标准输出 题目知识点 动态规划 \(dp\) 矩阵 矩阵乘法 矩阵加速 矩阵快速幂 ...

  5. 「P4994」「洛谷11月月赛」 终于结束的起点(枚举

    题目背景 终于结束的起点终于写下句点终于我们告别终于我们又回到原点…… 一个个 OIer 的竞赛生涯总是从一场 NOIp 开始,大多也在一场 NOIp 中结束,好似一次次轮回在不断上演.如果这次 NO ...

  6. 「洛谷4197」「BZOJ3545」peak【线段树合并】

    题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...

  7. 「洛谷3338」「ZJOI2014」力【FFT】

    题目链接 [BZOJ] [洛谷] 题解 首先我们需要对这个式子进行化简,否则对着这么大一坨东西只能暴力... \[F_i=\sum_{j<i} \frac{q_iq_j}{(i-j)^2}-\s ...

  8. 「BZOJ2733」「洛谷3224」「HNOI2012」永无乡【线段树合并】

    题目链接 [洛谷] 题解 很明显是要用线段树合并的. 对于当前的每一个连通块都建立一个权值线段树. 权值线段树处理操作中的\(k\)大的问题. 如果需要合并,那么就线段树暴力合并,时间复杂度是\(nl ...

  9. 「洛谷3870」「TJOI2009」开关【线段树】

    题目链接 [洛谷] 题解 来做一下水题来掩饰ZJOI2019考炸的心情QwQ. 很明显可以线段树. 维护两个值,\(Lazy\)懒标记表示当前区间是否需要翻转,\(s\)表示区间还有多少灯是亮着的. ...

随机推荐

  1. Redis集群搭建过程

    我在搭建Redis集群过程中遇到了一些问题,现记录下来. Redis搭建需要在系统中安装好ruby.gem.zlib等工具,可参考https://www.cnblogs.com/wuxl360/p/5 ...

  2. 在Linux添加PYTHONPATH方法以及修改环境变量方法

    Linux下设置环境变量有三种方法,一种用于当前终端,一种用于当前用户,一种用于所有用户: 一:用于当前终端: 在当前终端中输入: export PATH=$PATH:<你的要加入的路径> ...

  3. Non-Volatile Register 非易失性寄存器 调用约定对应寄存器使用

    非易失性寄存器(Non-volatile register)是它的内容必须通过子程序调用被保存的一个寄存器.如果一个程序改变了一个非易失性寄存器的值,它必须保存在改变这个寄存器之前堆栈中保存旧的值和在 ...

  4. 【转帖】理解 Linux 的虚拟内存

    理解 Linux 的虚拟内存 https://www.cnblogs.com/zhenbianshu/p/10300769.html 段页式内存 文章了里面讲了 页表 没讲段表 记得最开始的时候 学习 ...

  5. ToroiseGit提交代码上传到阿里云的Gitlab

    https://blog.csdn.net/xiaomogg/article/details/51903004(copy) 准备 具体过程 准备 1.拥有一个GitHub账户 2.安装了Tortois ...

  6. Angular 过滤器

    <!DOCTYPE html><html ng-app="myApp"><head lang="en"> <meta ...

  7. centOS7搭建NFS服务器

    借鉴别人这篇博客搭建成功的:http://blog.51cto.com/mrxiong2017/2087001 NFS系统:用来共享文件.图片.视频 准备两个centOS7服务器,一个作NFS ser ...

  8. Python Note1: Pycharm的安装与使用

    前言 曾经学过一段时间python,虽然现在工作了主要使用C#和C++,但是觉得还是有必要在业余的时候学习学习python,提升下自己的知识面,毕竟技多不压身,加油吧! 安装与激活Pycharm 个人 ...

  9. Junit概述

    Junit ->  java unit.也就是说Junit是xunit家族中的一员. unit   <- unit test case,即单元测试用例. Junit  = java uni ...

  10. Flutter之 LimitedBox、Offstage、OverflowBox、SizedBox详解

    1. LimitedBox A box that limits its size only when it's unconstrained. 1.1 简介 LimitedBox,通过字面意思,也可以猜 ...