bzoj 2286 [Sdoi2011]消耗战(虚树+树上DP)
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=2286
【题意】
给定一棵树,切断一条树边代价为ci,有m个询问,每次问使得1号点与查询的k个点不连通的最小代价。
【思路】
虚树+树上DP。
构建虚树,这里学了一个比较机智的构图方法:当询问点之间存在子孙后代关系时只保留最上面的节点。
在这种构图方式的基础上进行树上DP,设f[u]表示以u为根的子树,则有转移式:
f[u]=min{mn[u] , sum(f[v])},u不是资源点
f[u]=mn[u],u是资源点
其中mn[u]表示u到根的路径上的最短边。Ps:每个叶子都代表一个询问点,第二个抉择只是为了提供最短边都在u之下的情况,如果在u之上虽然会出现费用计算重合但这不是最优解所以无关紧要。
需要注意的是mx[1]赋大值,d[1]设为1,对应清空边表而非一次n的循环。另外vector中的clear()并不是释放空间,可以看作形如size=0的操作,所以不用担心初始化时间的问题。
LCA好像写得有点挫,效率不是很高的样子=-=
【代码】
#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std; typedef long long LL;
const int N = +;
const int D = ; struct Edge{ int u,v,w;
};
vector<Edge> es;
vector<int> g[N],G[N];
int fa[N][D],d[N],dfn[N],bin[D]; LL mx[N];
int n,m,dfsc; void adde(int u,int v,int w) {
es.push_back((Edge){u,v,w});
int m=es.size(); g[u].push_back(m-);
}
void adde2(int u,int v) {
if(u!=v) G[u].push_back(v); else return ;
//printf("es(%d,%d)\n",u,v);
}
bool cmp(const int& lhs,const int& rhs) { return dfn[lhs]<dfn[rhs];
} void dfs(int u) {
dfn[u]=++dfsc;
for(int i=;i<g[u].size();i++) {
Edge e=es[g[u][i]]; int v=e.v;
if(v!=fa[u][]) {
fa[v][]=u;
for(int j=;j<D;j++) fa[v][j]=fa[fa[v][j-]][j-];
d[v]=d[u]+; mx[v]=min(mx[u],(LL)e.w);
dfs(v);
}
}
}
int LCA(int u,int v) {
if(d[v]>d[u]) swap(u,v);
for(int i=D-;i>=;i--)
if(d[fa[u][i]]>=d[v]) u=fa[u][i];
if(u==v) return u;
for(int i=D-;i>=;i--)
if(fa[u][i]!=fa[v][i]) u=fa[u][i] , v=fa[v][i];
return fa[u][];
}
void read(int &x) {
char c=getchar(); while(!isdigit(c)) c=getchar();
x=; while(isdigit(c)) x=x*+c-'' , c=getchar();
}
LL f[N];
void dp(int u) {
LL tmp=;
for(int i=;i<G[u].size();i++) {
dp(G[u][i]);
tmp += f[G[u][i]];
}
G[u].clear(); //清空边表
f[u]=mx[u]; //f=mx 所以mx赋大值
if(tmp && tmp<f[u]) f[u]=tmp;
}
void solve() {
int top=,tot=,k;
static int st[N],h[N];
read(k);
for(int i=;i<=k;i++) read(h[i]) ;
sort(h+,h+k+,cmp);
///////////////////////////////////// 以下是一个十分机智的重新构图 from hzwer
h[++tot]=h[];
for(int i=;i<=k;i++)
if(LCA(h[tot],h[i])!=h[tot]) h[++tot]=h[i]; //虚树中不会出现询问点间的子孙后代关系
st[++top]=;
for(int i=;i<=tot;i++) {
int p=h[i],lca=LCA(p,st[top]);
for(;;) {
if(d[st[top-]]<=d[lca]) {
adde2(lca,st[top--]);
if(st[top]!=lca) st[++top]=lca;
break;
}
adde2(st[top-],st[top]); top--;
}
if(st[top]!=p) st[++top]=p;
}
while(--top) adde2(st[top],st[top+]);
/////////////////////////////////////
dp();
printf("%lld\n",f[]);
} int main() {
read(n);
int u,v,w;
for(int i=;i<n-;i++) {
read(u),read(v),read(w);
adde(u,v,w) , adde(v,u,w);
}
mx[]=1e18,d[]=; dfs(); //d[1]=1
read(m);
while(m--) solve();
return ;
}
bzoj 2286 [Sdoi2011]消耗战(虚树+树上DP)的更多相关文章
- BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序
https://www.lydsy.com/JudgeOnline/problem.php?id=2286 wa了两次因为lca犯了zz错误 这道题如果不多次询问的话就是裸dp. 一棵树上多次询问,且 ...
- BZOJ.2286.[SDOI2011]消耗战(虚树 树形DP)
题目链接 BZOJ 洛谷P2495 树形DP,对于每棵子树要么逐个删除其中要删除的边,要么直接断连向父节点的边. 如果当前点需要删除,那么直接断不需要再管子树. 复杂度O(m*n). 对于两个要删除的 ...
- bzoj 2286: [Sdoi2011]消耗战 虚树+树dp
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...
- bzoj 2286 [Sdoi2011]消耗战 虚树+dp
题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...
- BZOJ 2286 [Sdoi2011]消耗战 ——虚树
虚树第一题. 大概就是建一颗只与询问有关的更小的新树,然后在虚树上DP #include <map> #include <ctime> #include <cmath&g ...
- BZOJ 2286: [Sdoi2011]消耗战 虚树
Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军 ...
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
[题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...
- BZOJ2286: [Sdoi2011]消耗战(虚树/树形DP)
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5246 Solved: 1978[Submit][Status][Discuss] Descript ...
- luogu P2495 [SDOI2011]消耗战 |虚树+LCA+dp
题目描述 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知 ...
随机推荐
- 2014-11-9------- 设有一数据库,包括四个表:学生表(Student)、课程表(Course)、成绩表(Score)以及教师信息表(Teacher)。
一. 设有一数据库,包括四个表:学生表(Student).课程表(Course).成绩表(Score)以及教师信息表(Teacher).四个表的结构分别如表1-1的表(一)~表( ...
- the c programming language 2-3
#include<stdio.h> #define MAXLINELEN 1000 int power(int base,int n) { ; ; ;i<n;i++) answer= ...
- Java面向对象程序设计--与C++对比说明:系列1(面向对象基础)
面向对象程序设计作为一种重要的程序设计思想,在近些年来得到广泛的推崇.而Java和C++更是面向对象程序设计语言中的翘楚,要彻底摸清面向对象程序设计的精髓和在实际应用中更加高效的进行代码设计 ...
- 关于Html无宽度居中
代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title ...
- c++builder调用vc的dll
$bcb/bin目录中有个implib.exe 把你的vc.dll和implib.exe复制到c盘根目录下 运行cmd 进入c盘根目录执行 c:\implib -a cb.lib vc.dll 会生成 ...
- js 默认的参数、可变的参数、变量作用域
可以通过arguments对象来实现可变的参数 在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们. arguments是一个数组对象,可以通过下标来实别参数的位置 ...
- Centos7 修改运行级别
systemd使用比sysvinit的运行级别更为自由的target概念作为替代 第三运行级: multi-user.target 第五运行级: graphical.target #前者是符号链接 ...
- UML2.0统一建模语言
Unified Modeling Language (UML)又称统一建模语言或标准建模语言,是支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化支持,包括由需求分析到规 ...
- iOS: 学习笔记, 透过Boolean看Swift(译自: https://developer.apple.com/swift/blog/ Aug 5, 2014 Boolean)
透过Boolean看Swift 一个简单的Bool类型内部就包含了许多Swift主要功能, 如何构建一个简单类型是有趣的演示. 本文将创建一个与Bool类型在设计与实现上非常相似的新MyBool类型. ...
- 关于一个简单面试题(。net)
猫大叫一声,主人被惊醒,所有的小老鼠开始逃窜. 期初想到的是事件调用方法. 在猫叫的事件中调用一对方法就可以了. 但是,当事件很多的时候 难保大家写着写着就忘记了. 总不能有 10000个人的时候调用 ...