【题意】给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价。n<=250000,Σki<=500000。

【算法】虚树+DP

【题解】考虑普通树上的dp,设f[x]表示隔离1和子树x内特殊点的最小代价,val[x]表示x到1路径上的最小代价(预处理)。

点x特殊,f[x]=val[x]

否则,f[x]=min{val[x],Σf[y]},y=son[x]

在询问总数有限制的前提下,可以建虚树进行如上DP。

复杂度O(Σki log n)。

注意:

1.清空时垃圾回收,保证复杂度。

2.询问点数组开两倍,因为要加入两两LCA。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int read(){
int s=,t=;char c;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
const int maxn=;
struct edge{int v,w,from;}e[maxn*];
int in[maxn],ou[maxn],deep[maxn],f[maxn][],st[maxn],n,N,tot,first[maxn],a[maxn*];//a[]
bool v[maxn];
ll val[maxn]; namespace cyc{
struct edge{int v,w,from;}e[maxn*];
int first[maxn],dfsnum=,tot;
void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
void dfs(int x,int fa){
in[x]=++dfsnum;
for(int j=;(<<j)<=deep[x];j++)f[x][j]=f[f[x][j-]][j-];
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
deep[e[i].v]=deep[x]+;
val[e[i].v]=min(val[x],1ll*e[i].w);
f[e[i].v][]=x;
dfs(e[i].v,x);
}
ou[x]=dfsnum;
}
int lca(int x,int y){
if(deep[x]<deep[y])swap(x,y);
int d=deep[x]-deep[y];
for(int i=;i<=;i++)if((<<i)&d)x=f[x][i];
if(x==y)return x;
for(int i=;i>=;i--)if((<<i)<=deep[x]&&f[x][i]!=f[y][i]){
x=f[x][i];y=f[y][i];
}
return f[x][];
}
void build(){
n=read();
for(int i=;i<n;i++){
int u=read(),v=read(),w=read();
insert(u,v,w);insert(v,u,w);
}
val[]=1ll<<;//
dfs(,-);
}
}
void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
bool cmp(int a,int b){return in[a]<in[b];}
ll dp(int x){
if(v[x])return val[x];
ll sum=;
for(int i=first[x];i;i=e[i].from)sum+=dp(e[i].v);
return min(val[x],sum);
}
bool check(int x,int y){return in[y]<=in[x]&&ou[x]<=ou[y];}
void build(){
int last=read();N=last;
for(int i=;i<=N;i++)a[i]=read(),v[a[i]]=;//
sort(a+,a+N+,cmp);
for(int i=;i<last;i++)a[++N]=cyc::lca(a[i],a[i+]);
sort(a+,a+N+,cmp);
N=unique(a+,a+N+)-a-;
for(int i=;i<=N;i++)first[a[i]]=;tot=;//
int top=;
for(int i=;i<=N;i++){
while(top&&!check(a[i],st[top]))top--;
if(top)insert(st[top],a[i]);
st[++top]=a[i];
}
printf("%lld\n",dp(a[]));
for(int i=;i<=N;i++)v[a[i]]=;//
}
int main(){
cyc::build();
int m=read();
while(m--)build();
return ;
}

【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP的更多相关文章

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

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

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

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

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

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

  4. BZOJ.2286.[SDOI2011]消耗战(虚树 树形DP)

    题目链接 BZOJ 洛谷P2495 树形DP,对于每棵子树要么逐个删除其中要删除的边,要么直接断连向父节点的边. 如果当前点需要删除,那么直接断不需要再管子树. 复杂度O(m*n). 对于两个要删除的 ...

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

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

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

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

  7. [BZOJ2286][SDOI2011]消耗战(虚树DP)

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4998  Solved: 1867[Submit][Statu ...

  8. BZOJ 2286: [Sdoi2011]消耗战

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

  9. BZOJ 3572 [HNOI2014]世界树 (虚树+DP)

    题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ...

随机推荐

  1. bootstrap学习一

    bootstrap学习 一.css概览: 1.使用HTML5标准,<!DOCTYPE html>. 2.移动设备优先: <meta name="viewport" ...

  2. js 判断字符串中是否包含某个字符串

    String对象的方法 方法一: indexOf()   (推荐) var str = "123"; console.log(str.indexOf("3") ...

  3. java 遍历方法 及 数组,ArrayList,HashMap,HashSet的遍历

    一,遍历方法的实现原理 1.传统的for循环遍历,基于计数器的: 遍历者自己在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后,停止.主要就是需要按元素的位置来读取元素. ...

  4. Django(九)admin相关知识

    https://www.cnblogs.com/yuanchenqi/articles/6083427.htm https://www.cnblogs.com/haiyan123/p/8034430. ...

  5. Day035--Python--管道, Manager, 进程池, 线程切换

    管道 #创建管道的类: Pipe([duplex]):在进程之间创建一条管道,并返回元组(conn1,conn2),其中conn1,conn2表示管道两端的连接对象,强调一点:必须在产生Process ...

  6. pytest 7 assert断言

    前言:断言是自动化最终的目的,一个用例没有断言,就失去了自动化测试的意义了. 断言用到的是 assert关键字.之前的介绍,有的测试方法中其实用到了assert断言.简单的来说,就是预期的结果去和实际 ...

  7. Ubuntu下安装Goldendict(翻译软件)

    Ubuntu直接安装 sudo apt-get install goldendict 通过源码安装 失败 下载词典 http://blog.sina.com.cn/s/blog_c58823b3010 ...

  8. hdu 3530 "Subsequence" (单调队列)

    传送门 题意: 给出一个序列,求最长的连续子序列,使得 m ≤ Max-Min ≤ k 我的理解: 定义数组 a[] 存储输入的 n 个数: 定义两个双端队列: deque<int >qM ...

  9. poj 2566"Bound Found"(尺取法)

    传送门 参考资料: [1]:http://www.voidcn.com/article/p-huucvank-dv.html 题意: 题意就是找一个连续的子区间,使它的和的绝对值最接近target. ...

  10. linux driver ------ 字符设备驱动 之 “ 创建设备节点流程 ”

    在字符设备驱动开发的入门教程中,最常见的就是用device_create()函数来创建设备节点了,但是在之后阅读内核源码的过程中却很少见device_create()的踪影了,取而代之的是device ...