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)
二叉查找树 [题目描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值,每个结 ...
随机推荐
- 关于React中,map出来的元素添加事件问题
用es6 map 的写法 直接绑定一个onTouchStart 事件不会报错. 用es5的map写法 如果不加上this 会报这个错误 无法读取未定义的属性 解决的方法是 绑定this 就可以了
- Mycat常见问题与解决方案---宜将剩勇追穷寇,不可沽名学霸王
1 Mycat目前有哪些功能与特性? 答: • 支持 SQL 92标准 • 支持Mysql集群,可以作为Proxy使用 • 支持JDBC连接多数据库 • 支持NoSQL数据库 • 支持galera f ...
- Stable Matching (Gale Sharpley Algorithm)
稳定婚配问题:n个男生n个女生.当中每一个人都有自己心仪的列表. 问怎样达成稳定的匹配(比方, b想B求婚,可是B已有的对象的优先级高于b,此时b的魅力不足以拆散B所处的那一对,即达到稳定状态.) ( ...
- POJ2029:Get Many Persimmon Trees(二维树状数组)
Description Seiji Hayashi had been a professor of the Nisshinkan Samurai School in the domain of Aiz ...
- Altium Designer中DRC错误分析
- python3 turtle 画围棋棋盘
python3 环境 利用turtle模块画出 围棋棋盘 #!/usr/bin/env python # -*- coding:utf-8 -*- # Author:Hiuhung Wan impor ...
- GO语言学习(六)Go 语言数据类型
在 Go 编程语言中,数据类型用于声明函数和变量. 数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存. Go 语言按类别有以下几种 ...
- Android 使用XML隐藏ActionBar中遇错的解决的方法
今天我在使用Menifest.xml让程序隐藏标题栏是一直出错.主要内容是: You need to use a theme.AppCompat theme(descendant) with this ...
- UVA 11859 - Division Game
看题传送门 题目大意 有一个n * m的矩阵,每个元素均为2~10000之间的正整数,两个游戏者轮流操作.每次可选一行中的1个或者多个大于1的整数把它们中的每个数都变成它的某个真因子,比如12可以变成 ...
- Android系统开发(8)——linx进程基本概念
一.proc文件系统 传统意义上的文件系统是用于块设备上信息的存储,/proc这个目录是一个虚拟文件系统,它放置的数据都是在内存当中,所以这个目录本身不占用任何硬盘空间.主要包含如下系统信息: 内存管 ...