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)
二叉查找树 [题目描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值,每个结 ...
随机推荐
- CentOS6.X安装10G需要额外安装的软件包
yum -y install libXp yum -y install libXp.i686 yum -y install libXtst.i686
- 导出查询结果到csv文件
set colsep , set feedback off set heading off set trimout on spool my.csv select * from emp ...
- VIP的转移
首先查看vip在各个节点的状态 [root@rac2 ~]# ifconfig eth0 Link encap:Ethernet HWaddr 08:00:27:C9:28:D0 inet addr: ...
- css滑动鼠标到img后,切换图片
写了个样例: <a href="#"><img src="http://csdnimg.cn/pubfooter/images/gongshang_lo ...
- Python写爬虫-爬甘农大学校新闻
Python写网络爬虫(一) 关于Python: 学过C. 学过C++. 最后还是学Java来吃饭. 一直在Java的小世界里混迹. 有句话说: "Life is short, you ne ...
- 从数据表中随机抽取n条数据有哪几种方法(join实现可以先查数据然后再拼接)
从数据表中随机抽取n条数据有哪几种方法(join实现可以先查数据然后再拼接) 一.总结 一句话总结:最好的是这个:"SELECT * FROM table WHERE id >= (( ...
- [D3] Select DOM Elements with D3 v4
Before you can create dazzling data driven documents, you need to know how D3 accesses the DOM. This ...
- 自旋锁spinlock解析
1 基础概念 自旋锁与相互排斥锁有点类似,仅仅是自旋锁不会引起调用者睡眠.假设自旋锁已经被别的运行单元保持.调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁."自旋"一词就 ...
- POJ 1595 Prime Cuts (ZOJ 1312) 素数打表
ZOJ:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=312 POJ:http://poj.org/problem?id=159 ...
- [Angular] Learn How To Use ng-template Inputs
For example, we have a modal component, it can config that using ng-template as a configurable templ ...
