题目链接 BZOJ

洛谷P2495

树形DP,对于每棵子树要么逐个删除其中要删除的边,要么直接断连向父节点的边。

如果当前点需要删除,那么直接断不需要再管子树。

复杂度O(m*n)。

对于两个要删除的点 u,v 之间的链,若链上没有其它需要删的点,则只需保留链上的最小边权即可。

把有用的点按DFS序排序,依次构建出一棵虚树,可以在上面进行同样的DP。

代码在下面

这儿是虚树构建详细过程(这图有点。。图可以拖到后台打开):

参考:https://www.cnblogs.com/Michael-Li/p/8763242.html









这个算数据结构么。。

卡常技巧:

本题建虚树时,对于某要删除点的子树中的点,都可以忽略,即Insert时若LCA(sk[top],now)=sk[top],可直接忽略now的入栈。(因为刚开始栈顶一定是个要删的点)

这样就可以用表头是否为空来判断是否要删除该点了,不需要标记。

本题建虚树时不需要边权,直接用点权即可,权值为到根路径的最小边权。

还因为是棵树,那么连边时用链表即可,不需要用边表。(然并软。。还是用边表吧)

//17428kb	3264ms(Rank4 嗯...)
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 1000000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=250005,M=N<<1; int n,m,K,A[N],Enum,H[N],nxt[M],to[M],len[M],val[N],dfn[N],Index,fa[N],tp[N],sz[N],son[N],dep[N],top,sk[N];
char IN[MAXIN],*SS=IN,*TT=IN; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void AddEdge(int u,int v,int w){
to[++Enum]=v, nxt[Enum]=H[u], len[Enum]=w, H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], len[Enum]=w, H[v]=Enum;
}
inline void Add_direct(int u,int v){
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
}
inline bool cmp_dfn(const int &a,const int &b){
return dfn[a]<dfn[b];
}
void DFS1(int x,int mn)
{
int mx=0; sz[x]=1, val[x]=mn;
for(int v,i=H[x]; i; i=nxt[i])
if((v=to[i])!=fa[x])
{
fa[v]=x, dep[v]=dep[x]+1, DFS1(v,std::min(mn,len[i])), sz[x]+=sz[v];
if(mx<sz[v]) mx=sz[v], son[x]=v;
}
}
void DFS2(int x,int _tp)
{
dfn[x]=++Index, tp[x]=_tp;
if(son[x])
{
DFS2(son[x],_tp);
for(int i=H[x]; i; i=nxt[i])
if(to[i]!=fa[x]&&to[i]!=son[x]) DFS2(to[i],to[i]);
}
}
int LCA(int u,int v)
{
while(tp[u]!=tp[v]) dep[tp[u]]>dep[tp[v]]?u=fa[tp[u]]:v=fa[tp[v]];
return dep[u]<dep[v]?u:v;
}
void Insert(int p)
{
if(top==1) {sk[++top]=p; return;}//if(sk[top]==1)
int lca=LCA(sk[top],p);
if(lca==sk[top]) return;
// int las=sk[top];
// while(lca!=las)
// {
// if(dfn[sk[--top]]<dfn[lca])
// {
// Add_direct(lca,las), sk[++top]=lca;
// break;
// }
// Add_direct(sk[top],las), las=sk[top];
// }
while(dfn[sk[top-1]]>=dfn[lca]) Add_direct(sk[top],sk[top--]);//参数调用顺序...还是写个las=sk[top]吧
if(lca!=sk[top] && dfn[sk[top-1]]<dfn[lca]) Add_direct(lca,sk[top]), sk[top]=lca;//++top, --top
sk[++top]=p;
}
LL DP(int x)
{
if(!H[x]) return val[x];
LL sum=0;
for(int i=H[x]; i; i=nxt[i]) sum+=DP(to[i]);
H[x]=0;
return std::min((LL)val[x],sum);
} int main()
{
n=read();
for(int u,v,i=1; i<n; ++i) u=read(),v=read(),AddEdge(u,v,read());
DFS1(1,0x7fffffff), DFS2(1,1), Enum=0, memset(H,0,sizeof H);
m=read();
while(m--)
{
K=read();
for(int i=1; i<=K; ++i) A[i]=read();
std::sort(A+1,A+1+K,cmp_dfn);
sk[top=1]=1;
for(int i=1; i<=K; ++i) Insert(A[i]);
while(--top) Add_direct(sk[top],sk[top+1]); LL res=0;
for(int i=H[1]; i; i=nxt[i]) res+=DP(to[i]);//对1要单独处理,要不应把val[1]设为很大的longlong
H[1]=0;
printf("%lld\n",res);
Enum=0; //for(int i=1; i<=K; ++i) H[A[i]]=0;
}
return 0;
}

BZOJ.2286.[SDOI2011]消耗战(虚树 树形DP)的更多相关文章

  1. BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序

    https://www.lydsy.com/JudgeOnline/problem.php?id=2286 wa了两次因为lca犯了zz错误 这道题如果不多次询问的话就是裸dp. 一棵树上多次询问,且 ...

  2. bzoj 2286: [Sdoi2011]消耗战 虚树+树dp

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...

  3. bzoj 2286 [Sdoi2011]消耗战 虚树+dp

    题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...

  4. BZOJ 2286: [Sdoi2011]消耗战 虚树

    Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军 ...

  5. BZOJ2286: [Sdoi2011]消耗战(虚树/树形DP)

    Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5246  Solved: 1978[Submit][Status][Discuss] Descript ...

  6. BZOJ 2286 [Sdoi2011]消耗战 ——虚树

    虚树第一题. 大概就是建一颗只与询问有关的更小的新树,然后在虚树上DP #include <map> #include <ctime> #include <cmath&g ...

  7. 【BZOJ-2286】消耗战 虚树 + 树形DP

    2286: [Sdoi2011消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2120  Solved: 752[Submit][Status] ...

  8. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...

  9. 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP

    [题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...

随机推荐

  1. Treats for the Cows 区间DP POJ 3186

    题目来源:http://poj.org/problem?id=3186 (http://www.fjutacm.com/Problem.jsp?pid=1389) /** 题目意思: 约翰经常给产奶量 ...

  2. IDL界面程序直接调用envi菜单对应功能

    参考自http://blog.sina.com.cn/s/blog_764b1e9d010115qu.html 参考文章的方法是构建一个button控件,通过单击实现,这种方法比较复杂,不是我们经常能 ...

  3. OpenStack 监控解决方案

    正如你们看到的那样,到目前为止(OpenStack Kilo),OpenStack自己的监控组件Telemetry并不是完美, 获取的监控数据以及制作出来的图表有时候让人匪夷所思,因其重点并不是监控而 ...

  4. JQuery中DOM事件合成用法

    jQuery有两个合成事件——hover()方法和toggle()方法 类似前面讲过的ready()方法,hover()方法和toggle()方法都属于jQuery自定义的方法. hover()方法: ...

  5. vue项目中,Iview打包到生产环境时, woff 字体引用问题

    出现这问题的原因是文件路径不对,与webpack有关,解决的办法为: 一.修改webpack.prod.conf.js module: { rules: utils.styleLoaders({ so ...

  6. java基础19 导包和“命令行”打jar包

    1.导包 1.1.包 java中的包就相当于Windows文件夹        编译格式:javac -d . 类名.java 1.2.包的作用 1.解决了类名重复冲突的问题    2.便于软件版本的 ...

  7. 用HTML+CSS实现--折叠效果

    下图是一个Accordion组件,请用HTML+CSS实现其UI,并用面向对象的思路把折叠效果JS实现.如果能用纯css的方式实现其折叠效果更佳.PS/这是小米15年的一道校招笔试题,无意间看到就实现 ...

  8. hdu 3951 硬币围成一圈(博弈)

    n个硬币围成一个环 每次只能取1-K个硬币 最后取完者胜 假如5个硬币 每次取1-2个情况1 先手取1个 后手取剩下4个中间2个 破坏了连续 虽然最后剩2个,但先手只能取一个 然后后再取一个 后手胜 ...

  9. CentOS7.5安装MongoDB4.0与CRUD基本操作

    一 MongoDB简介 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数 ...

  10. Linux mint 17.3系统安装及常用开发办公软件部署

    关于为什么选择linuxmint17.3作为个人办公开发系统的选择说明: 编者按]提起Linux系统,大家可能最先想到的就是 Linux Mint 和 Ubuntu 两个版本了.近来,开源界貌似激进了 ...