bzoj 2286 [Sdoi2011]消耗战 虚树+dp
题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用
分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用
对于父亲x,儿子y
①y为关键点:\(dp[x]\)+=\(dismn(x,y)\)
②y不为关键点:要么断y,要么断y所有子树
\(dp[x]\)+=\(min(dismn(x,y),dp[y])\)
=========================================================
关于兼容性的一种讨论
dismn(x,y)直接改为dismn(1,x)预处理算可以吗
当然不行?
交一发,A
兼容性:若要算到y,则y到1路径中没有关键点
①情况无影响
②情况中若子树中最小值算到了上面,断y定更优,而断y又变成父节点的①②情况讨论
所以是可以的咯
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long LL;
const int M=250007;
inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=0;
for(;isdigit(c);c=getchar())x=x*10+c-48;
return f?x:-x;
}
int n,m;
LL dp[M];
LL dis[M];
LL w[M][20];
int ln[M];
int dep[M],sz[M],son[M],pre[M];
int top[M],dfn[M],pid[M],T;
int que[M],kd[M];
bool cmp(int x,int y){return dfn[x]<dfn[y];}
int st[M],tot;
int g[M],te;
struct edge{int y,next;LL d;}e[M<<1];
void addedge(int x,int y,LL d){
e[++te].y=y;e[te].d=d;e[te].next=g[x];g[x]=te;
}
int hd[M],td;
struct link{int y,next;}dw[M];
void addlink(int x,int y){
if(x==y)return;
dw[++td].y=y;dw[td].next=hd[x];hd[x]=td;
}
void dfs1(int x){
sz[x]=1;
int p,y;
for(p=g[x];p;p=e[p].next)
if((y=e[p].y)!=pre[x]){
dep[y]=dep[x]+1;
dis[y]=e[p].d;
pre[y]=x;
dfs1(y);
sz[x]+=sz[y];
if(sz[y]>sz[son[x]]) son[x]=y;
}
}
void dfs2(int x){
pid[dfn[x]=++T]=x;
if(son[x]){
top[son[x]]=top[x];
dfs2(son[x]);
}
int p,y;
for(p=g[x];p;p=e[p].next)
if((y=e[p].y)!=pre[x]&&y!=son[x]){
top[y]=y;
dfs2(y);
}
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=pre[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return x;
}
void vbuild(int z){
int i,x,anc;
sort(que+1,que+z+1,cmp);
for(i=1;i<z;i++){
anc=LCA(que[i],que[i+1]);
hd[anc]=0; kd[anc]=2; dp[anc]=0;
}
hd[1]=0; dp[1]=0;//*****
for(i=1;i<=z;i++){
x=que[i];
hd[x]=0; kd[x]=1; dp[x]=0;
}
td=0;
tot=0;
st[++tot]=1;
for(i=1;i<=z;i++){
x=que[i];
anc=LCA(x,st[tot]);
if(anc==st[tot]){
st[++tot]=x;
continue;
}
else{
while( tot>1 && dep[anc]<=dep[st[tot-1]]){
addlink(st[tot-1],st[tot]);
tot--;
}
addlink(anc,st[tot]);
st[tot]=anc;
st[++tot]=x;
}
}
for(i=1;i<tot;i++) addlink(st[i],st[i+1]);
}
LL getm(int x,int y){
int l=ln[y-x+1];
return min(w[x][l],w[y-(1<<l)+1][l]);
}
void init(){
int i,j,l;
for(i=2;i<=n;i++) ln[i]=ln[i>>1]+1;
for(i=1;i<=n;i++) w[i][0]=dis[pid[i]];
for(i=n;i>0;i--){
l=ln[n-i+1];
for(j=1;j<=l;j++) w[i][j]=min(w[i][j-1],w[i+(1<<j-1)][j-1]);
}
}
LL getw(int x,int y){
LL res=1LL<<61;
while(dep[top[x]]>dep[y]){
res=min(res,getm(dfn[top[x]],dfn[x]));
x=pre[top[x]];
}
if(x!=y) res=min(res,getm(dfn[y]+1,dfn[x]));
return res;
}
void dfs(int x){
int p,y;
LL tp;
for(p=hd[x];p;p=dw[p].next){
y=dw[p].y;
tp=getw(y,x);
if(kd[y]==1) dp[x]+=tp;
else{
dfs(y);
dp[x]+=min(tp,dp[y]);
}
}
}
int main(){
int i,x,y,z;
n=rd();
for(i=1;i<n;i++){
x=rd(),y=rd(),z=rd();
addedge(x,y,z);
addedge(y,x,z);
}
dep[1]=pre[1]=0;
dis[1]=0;
dfs1(1);
top[1]=1;
dfs2(1);
init();
m=rd();
while(m--){
z=rd();
for(i=1;i<=z;i++) que[i]=rd();
vbuild(z);
dfs(1);
printf("%lld\n",dp[1]);
}
return 0;
}
bzoj 2286 [Sdoi2011]消耗战 虚树+dp的更多相关文章
- bzoj 2286: [Sdoi2011]消耗战 虚树+树dp
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
[题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...
- 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 #include <map> #include <ctime> #include <cmath&g ...
- BZOJ 2286: [Sdoi2011]消耗战 虚树
Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军 ...
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4998 Solved: 1867[Submit][Statu ...
- BZOJ 2286: [Sdoi2011]消耗战
2286: [Sdoi2011消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2082 Solved: 736[Submit][Status] ...
- BZOJ 3572 [HNOI2014]世界树 (虚树+DP)
题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ...
随机推荐
- SQL求解两个时间差
sql 求解两个时间差 SELECTDATEDIFF( Second, '2009-8-25 12:15:12', '2009-9-1 7:18:20') --返回相差秒数 SELECTDATEDIF ...
- fiddler2 中文乱码问题
打开注册表编辑器,找到HKCU\Software\Microsoft\Fiddler2\,在里面添加一个字符串值,名叫HeaderEncoding,值设置为默认编码.建议设成GB18030.然后要记得 ...
- How to spend you day ?
如果这是你生命中的最后的一天,你该如何去过好它呢? 不要浪费你生命中的每一分,每一秒!!!
- cin 与 scanf 的不同
cin输入更方便: 首先,cin 是个C++类型对象,它的类型是basic_istream,scanf 是个不定参数的函数,其次,cin 所属的类重载了 >> 运算符,使输入更简单了,比如 ...
- PAT (Advanced Level) 1049. Counting Ones (30)
数位DP.dp[i][j]表示i位,最高位为j的情况下总共有多少1. #include<iostream> #include<cstring> #include<cmat ...
- BodyContent揭秘及定制复杂的JSP标签
BodyContent揭秘及定制复杂的JSP标签 标签: jspintegerwrapperclass设计模式 2010-08-30 11:30 4555人阅读 评论(0) 收藏 举报 分类: HT ...
- PHP模板解析类实例
作者:mckee 这篇文章主要介绍了PHP模板解析类,涉及php针对模板文件的解析与字符串处理的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下 <?php class template { ...
- 基于Verilog HDL 各种实验
菜鸟做的的小实验链接汇总: 1.基于Verilog HDL 的数字时钟设计 2.乘法器 3.触发器(基本的SR触发器.同步触发器.D触发器) 4.基于Verilog HDL的ADC ...
- treeview 与tabControl组合使用
1.左边一个treeview,右边一个tabcontrol: 2.调整控件让tree在tabcontrol上,并让treeview压住tab页 3.将tab页的name设置成treeview的node ...
- CodeForces 484D Kindergarten
贪心观察+DP决策. 首先需要观察到一个结论:分割后的每一段肯定是单调增或者单调减的. 然后可以根据dp来决策如何分割价值最多. dp[i][0]表示放完第i个,最后一段是递减的情况下的最大价值 dp ...