BZOJ 2286 消耗战 - 虚树 + 树型dp
题目大意:
每次给出k个特殊点,回答将这些特殊点与根节点断开至少需要多少代价。
题目分析:
虚树
入门 + 树型dp:
刚刚学习完虚树(好文),就来这道入门题签个到。
虚树就是将树中的一些关键点提取出来,在不改变父子关系的条件下用$O(mlog n) \(组成一颗新树(m特殊点数,n总数),大小为\)O(m)$,以便降低后续dp等的复杂度。
建好虚树过后就可以进行普通的dp了(mn[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的更多相关文章
- BZOJ 2286 消耗战 (虚树+树形DP)
给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...
- BZOJ 2286 消耗战
虚树裸题. 23333以后memset千万慎用. #include<iostream> #include<cstdio> #include<cstring> #in ...
- bzoj 2286: [Sdoi2011]消耗战 虚树+树dp
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...
- BZOJ 2286 [Sdoi2011]消耗战(虚树+树形DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2286 [题目大意] 出一棵边权树,每次给出一些关键点,求最小边割集, 使得1点与各个关 ...
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
[题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...
- <虚树+树型DP> SDOI2011消耗战
<虚树+树型DP> SDOI2011消耗战 #include <iostream> #include <cstdio> #include <cstring&g ...
- <虚树+树型DP> HNOI2014世界树
<虚树+树型DP> HNOI2014世界树 #include <iostream> #include <cstdio> #include <cstring&g ...
- 虚树+【BZOJ2286】【SDOI2011】消耗战(虚树)(DP)
先看一道题: [BZOJ2286][SDOI2011]消耗战 Description 在一场战争中,战场由n个岛屿和n−1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总 ...
- BZOJ 1564 :[NOI2009]二叉查找树(树型DP)
二叉查找树 [题目描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值,每个结 ...
随机推荐
- Android检测网络状态,判断当前网络是否可用
用户手机当前网络可用:WIFI.2G/3G网络,用户打开与不打开网络,和是否可以用是两码事.可以使用指的是:用户打开网络了并且可以连上互联网进行上网. 检测当前网络是否可用,代码如下: /** * 检 ...
- [Vue] Load components when needed with Vue async components
In large applications, dividing the application into smaller chunks is often times necessary. In thi ...
- Android 利用an框架快速实现夜间模式的两种套路
作者:Bgwan链接:https://zhuanlan.zhihu.com/p/22520818来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 网上看到过大多实现夜间模 ...
- PHP解决约瑟夫环问题
PHP解决约瑟夫环问题 一.总结 二.PHP解决约瑟夫环问题 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到 ...
- 自定义 matplotlib 设置
Customizing plots with style sheets import matplotlib as mpl 查看配置文件所在的目录:mpl.get_configdir() 1. 自定义 ...
- Elasticsearch 2.3.2 从oracle中同步数据
Elasticsearch 2.3.2 从oracle中同步数据 1 数据批量导入-oracle 采用 elasticsearch-jdbc 插件 安装.版本需要ES版本一致 最新 ...
- Spring Boot初步认识
Spring Boot 来源及背后 Spring Boot开发始于 2013 年,伴随Spring4.0而生,2014 年 4 月发布 1.0.0 版本.当前版本1.4.0,http://projec ...
- idea+springboot+freemarker热部署(转)
今天在学习springboot集成freemarker模板引擎修改代码时,发现每次修改一次freemarker文件时,都必须重启下应用,浏览器刷新才能显示修改后的内容,这样效率太低,每次启动一次应用都 ...
- Injector Job深入分析 分类: H3_NUTCH 2015-03-10 15:44 334人阅读 评论(0) 收藏
Injector Job的主要功能是根据crawlId在hbase中创建一个表,将将文本中的seed注入表中. (一)命令执行 1.运行命令 [jediael@master local]$ bin/n ...
- URL validation failed. The error could have been caused through the use of the browser's navigation
URL validation failed. The error could have been caused through the use of the browser's navigation ...