传送门

题目大意:

每次给出k个特殊点,回答将这些特殊点与根节点断开至少需要多少代价。

题目分析:

虚树入门 + 树型dp:

刚刚学习完虚树(好文),就来这道入门题签个到。

虚树就是将树中的一些关键点提取出来,在不改变父子关系的条件下用$O(mlog n) \(组成一颗新树(m特殊点数,n总数),大小为\)O(m)$,以便降低后续dp等的复杂度。

建好虚树过后就可以进行普通的dp了(mn[u]表示原图中u到根节点的最短边长):

\[dp[u] = mn[u] (u是特殊点)
\]

\[dp[u] = min(mn[u], \sum{dp[son[u]]}) (u不是特殊点)
\]

此题就当做是虚树模板了。

注意每一次重建虚树时不用将1~n的边信息全部清空,不然你会见识到clear的惊人速度(T飞)。

code

#include<bits/stdc++.h>
using namespace std;
#define maxn 250050
#define oo 0x3f3f3f3f
typedef long long ll;
typedef pair<int, ll> pil;
namespace IO{
inline int read(){
int i = 0, f = 1; char ch = getchar();
for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
if(ch == '-') f = -1, ch = getchar();
for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
return i * f;
}
inline void wr(ll x){
if(x < 0) x = -x, putchar('-');
if(x > 9) wr(x / 10);
putchar(x % 10 + '0');
}
}using namespace IO;
int n, m;
vector<pil> g[maxn];
vector<int> vg[maxn];
ll dp[maxn], mn[maxn];
int dfn[maxn], clk, dep[maxn], vir[maxn], virCnt, par[maxn], rt;
bool key[maxn];
namespace LCA{
int pos[maxn], top[maxn], son[maxn], sze[maxn], tot, fa[maxn];
inline void dfs1(int u, int f){
dfn[u] = ++clk;
dep[u] = dep[f] + 1;
fa[u] = f;
sze[u] = 1;
for(int i = g[u].size() - 1; i >= 0; i--){
int v = g[u][i].first;
if(v == f) continue;
mn[v] = min(mn[u], g[u][i].second);
dfs1(v, u);
sze[u] += sze[v];
if(sze[v] > sze[son[u]] || !son[u]) son[u] = v;
}
}
inline void dfs2(int u, int f){
if(son[u]){
pos[son[u]] = ++tot;
top[son[u]] = top[u];
dfs2(son[u], u);
}
for(int i = g[u].size() - 1; i >= 0; i--){
int v = g[u][i].first;
if(v == f || v == son[u]) continue;
pos[v] = ++tot;
top[v] = v;
dfs2(v, u);
}
}
inline void splitTree(){
dfs1(1, 0);
pos[tot = 1] = top[1] = 1;
dfs2(1, 0);
}
inline int getLca(int u, int v){
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]]) swap(u, v);
u = fa[top[u]];
}
return dep[u] < dep[v] ? u : v;
}
} inline bool cmp(int u, int v){
return dfn[u] < dfn[v];
} inline void buildVir(){
static int stk[maxn], top;
top = 0;
sort(vir + 1, vir + virCnt + 1, cmp);
int oriSze = virCnt;
for(int i = 1; i <= oriSze; i++){
int u = vir[i];
if(!top){
stk[++top] = u;
par[u] = 0;
continue;
}
int lca = LCA::getLca(stk[top], u);
while(dep[lca] < dep[stk[top]]){
if(dep[stk[top - 1]] < dep[lca]) par[stk[top]] = lca;
--top;
}
if(lca != stk[top]){
vir[++virCnt] = lca;
par[lca] = stk[top];
stk[++top] = lca;
}
par[u] = lca;
stk[++top] = u;
}
for(int i = 1; i <= virCnt; i++) vg[vir[i]].clear();
for(int i = 1; i <= virCnt; i++){
int u = vir[i];
key[u] = ((i <= oriSze) ? 1 : 0);
if(par[u]) vg[par[u]].push_back(u);
}
sort(vir + 1, vir + virCnt + 1, cmp);
} inline void DP(int u){
// cout<<u<<"!";
ll ret = 0;
for(int i = vg[u].size() - 1; i >= 0; i--){
int v = vg[u][i];
DP(v);
ret += dp[v];
}
if(key[u]) dp[u] = mn[u];
else dp[u] = min(mn[u], ret);
} inline void solve(){
buildVir();
DP(vir[1]);
wr(dp[vir[1]]);
putchar('\n');
} int main(){
freopen("h.in", "r", stdin);
n = read();
for(int i = 1; i < n; i++){
int x = read(), y = read();
ll c = 1ll * read();
g[x].push_back(pil(y, c));
g[y].push_back(pil(x, c));
}
memset(mn, oo, sizeof mn);
LCA::splitTree();
m = read();
for(int i = 1; i <= m; i++){
int k = read();
virCnt = 0;
for(int j = 1; j <= k; j++)
vir[++virCnt] = read();
solve();
}
return 0;
}

BZOJ 2286 消耗战 - 虚树 + 树型dp的更多相关文章

  1. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...

  2. BZOJ 2286 消耗战

    虚树裸题. 23333以后memset千万慎用. #include<iostream> #include<cstdio> #include<cstring> #in ...

  3. bzoj 2286: [Sdoi2011]消耗战 虚树+树dp

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...

  4. BZOJ 2286 [Sdoi2011]消耗战(虚树+树形DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2286 [题目大意] 出一棵边权树,每次给出一些关键点,求最小边割集, 使得1点与各个关 ...

  5. 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP

    [题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...

  6. <虚树+树型DP> SDOI2011消耗战

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

  7. <虚树+树型DP> HNOI2014世界树

    <虚树+树型DP> HNOI2014世界树 #include <iostream> #include <cstdio> #include <cstring&g ...

  8. 虚树+【BZOJ2286】【SDOI2011】消耗战(虚树)(DP)

    先看一道题: [BZOJ2286][SDOI2011]消耗战 Description 在一场战争中,战场由n个岛屿和n−1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总 ...

  9. BZOJ 1564 :[NOI2009]二叉查找树(树型DP)

    二叉查找树 [题目描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值,每个结 ...

随机推荐

  1. ADO.net简单增删改查

    嘿嘿,又到了总结了的时间,今天我们学习了ADO.net,什么是ADO.NET:ADO.NET就是一组类库,这组类库可以让我们通过程序的方式访问数据库,就像System.IO下的类操作文件一样, Sys ...

  2. 前端面试题(webpack)

    (前端面试题大全,持续更新) webpack3升级到4为什么会提升速度? webpack优化有哪些? webpack的css-loader原理讲一下 webpack压缩js css的方法

  3. 图像处理 Mine

    1)中值滤波:排序取中间值.作用:去噪点 1.1)均值滤波; 1.2)高斯模糊:执行高斯模糊,然后改混合模式,改成叠加.柔光或者深色.就能得到平滑而不模糊的效果. 2)腐蚀.膨胀:开运算(腐蚀后膨胀) ...

  4. JSP中的EL表达式详细介绍

    一.JSP EL语言定义 EL 提供了在 JSP 脚本编制元素范围外使用运行时表达式的功能.脚本编制元素是指页面中能够用于在 JSP 文件中嵌入 Java 代码的元素.它们通常用于对象操作以及执行那些 ...

  5. HTTP详解--请求、响应、缓存

    1. HTTP请求格式 做过Socket编程的人都知道,当我们设计一个通信协议时,“消息头/消息体”的分割方式是很常用的,消息头告诉对方这个消息是干什么的,消息体告诉对方怎么干.HTTP协议传输的消息 ...

  6. 微服务实践(七):从单体式架构迁移到微服务架构 - DockOne.io

    原文:微服务实践(七):从单体式架构迁移到微服务架构 - DockOne.io [编者的话]这是用微服务开发应用系列博客的第七篇也是最后一篇.第一篇中介绍了微服务架构模式,并且讨论了微服架构的优缺点: ...

  7. pat 2-05. 求集合数据的均方差(水题)

    代码: #include<cstdio> #include<iostream> #include<cmath> using namespace std; doubl ...

  8. OAuth2 社区通用组件

    转载:http://www.cyqdata.com/download/article-detail-54302   使用本组件,只需要几行代码,就可以在网站上集成以下效果:     相关文章及使用说明 ...

  9. Android 蓝牙扫描代码

    /** * Created by rbq on 2016/11/1. */ import android.bluetooth.BluetoothAdapter; import android.blue ...

  10. Redis笔记---set

    1.redis set的介绍 集合中的数据是不重复且没有顺序,集合类型和列表类型的对比. 集合类型:存储的是的是最多2的32次方减一个字符串,数据是没有顺序的,但是数据是唯一的 列表类型:最多存储内容 ...