题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权。

共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价。

对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1

思路:第一题虚树,需要详细地记录一下。

对于此题,朴素的树形DP很好理解:

dp[u]为将u子树中的关键点全部切断的最小代价

dp[u]=min(cut[u],sigma(dp[v])) 其中cut[u]为1到u中最小的边权

但因为询问有多次且需要切断的关键点不同,会超时

经过思考可以发现只有很少的点需要被作为关键点进行处理:当一个点是关键点,或者为某两个关键点的LCA时,这个点会被作为关键点

显然关键点的数量是O(n)级别的

对于每次询问重新构造一棵虚树,使用栈

现将关键点按DFS序从小到大排序

对于一条链上的点只需保留两个

设新插入的点为x,栈顶的第一个点为y,第二个点为z,x与y的LCA为w:

1.dfn[w]<dfn[z] (w,x)连边,x入栈

2.dfn[w]=dfn[z] (y,z)连边

3.dfn[w]>dfn[z] 将w加入栈,(w,z),(w,x)之间连边

 const oo=;
var head,vet,next,len,head1,vet1,next1,
dep,flag,dfn,b,h,stk:array[..]of longint;
dp,cut:array[..]of int64;
f:array[..,..]of longint;
n,i,x,y,z,tot,time,que:longint; procedure add(a,b,c:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
len[tot]:=c;
head[a]:=tot;
end; function min(x,y:int64):int64;
begin
if x<y then exit(x);
exit(y);
end; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; function lca(x,y:longint):longint;
var i,d:longint;
begin
if dep[x]<dep[y] then swap(x,y);
d:=dep[x]-dep[y];
for i:= to do
if d and (<<i)> then x:=f[x,i];
for i:= downto do
if f[x,i]<>f[y,i] then
begin
x:=f[x,i]; y:=f[y,i];
end;
if x=y then exit(x);
exit(f[x,]);
end; procedure dfs(u:longint);
var e,i,v:longint;
begin
for i:= to do
begin
if dep[u]<(<<i) then break;
f[u,i]:=f[f[u,i-],i-];
end;
inc(time); dfn[u]:=time;
flag[u]:=;
e:=head[u];
while e<> do
begin
v:=vet[e];
if flag[v]= then
begin
f[v,]:=u;
dep[v]:=dep[u]+;
cut[v]:=min(cut[u],len[e]);
dfs(v);
end;
e:=next[e];
end;
end; procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
i:=l; j:=r; mid:=b[(l+r)>>];
repeat
while mid>b[i] do inc(i);
while mid<b[j] do dec(j);
if i<=j then
begin
swap(h[i],h[j]);
swap(b[i],b[j]);
inc(i); dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end; procedure add1(a,b:longint);
begin
if a=b then exit;
// writeln(a,' ',b);
inc(tot);
next1[tot]:=head1[a];
vet1[tot]:=b;
head1[a]:=tot;
end; procedure dfs2(u:longint);
var e,v:longint;
s:int64;
begin
e:=head1[u]; dp[u]:=cut[u];
s:=;
while e<> do
begin
v:=vet1[e];
dfs2(v);
s:=s+dp[v];
e:=next1[e];
end;
head1[u]:=;
if s= then dp[u]:=cut[u]
else dp[u]:=min(s,dp[u]);
end; procedure solve;
var m,i,top,now,p,q:longint;
begin
read(m); tot:=;
for i:= to m do begin read(h[i]); b[i]:=dfn[h[i]]; end;
qsort(,m);
q:=;
for i:= to m do
if lca(h[q],h[i])<>h[q] then begin inc(q); h[q]:=h[i]; end;
//for i:= to q do writeln(h[i]);
stk[]:=; top:=;
for i:= to q do
begin
now:=h[i]; p:=lca(now,stk[top]);
while true do
begin
if dep[p]>=dep[stk[top-]] then
begin
add1(p,stk[top]); dec(top);
if stk[top]<>p then begin inc(top); stk[top]:=p; end;
break;
end;
add1(stk[top-],stk[top]); dec(top);
end;
if stk[top]<>now then begin inc(top); stk[top]:=now; end;
end;
repeat
dec(top);
if top<= then break;
add1(stk[top],stk[top+]);
until top=;
dfs2();
writeln(dp[]);
end; begin
assign(input,'bzoj2286.in'); reset(input);
assign(output,'bzoj2286.out'); rewrite(output);
readln(n);
for i:= to n- do
begin
readln(x,y,z);
add(x,y,z);
add(y,x,z);
end;
readln(que);
//fillchar(cut,sizeof(cut),$1f);
cut[]:=oo;
dfs();
for i:= to que do solve;
close(input);
close(output);
end.

【BZOJ2286】消耗战(虚树,DFS序,树形DP)的更多相关文章

  1. 【BZOJ】3991: [SDOI2015]寻宝游戏 虚树+DFS序+set

    [题意]给定n个点的带边权树,对于树上存在的若干特殊点,要求任选一个点开始将所有特殊点走遍后返回.现在初始没有特殊点,m次操作每次增加或减少一个特殊点,求每次操作后的总代价.n,m<=10^5. ...

  2. [JSOI2016]最佳团体 DFS序/树形DP

    题目 洛谷 P4322 [JSOI2016]最佳团体 Description 茜茜的舞蹈团队一共有\(N\)名候选人,这些候选人从\(1\)到\(N\)编号.方便起见,茜茜的编号是\(0\)号.每个候 ...

  3. [SDOI2011][bzoj2286] 消耗战 [虚树+dp]

    题面: 传送门 思路: 看到所有询问中的点数总和是十万级别的,就想到用虚树~\(≧▽≦)/~啦 首先,树形dp应该是很明显可以看出来的: 设dp[u]表示以u为根的子树(不包括u)中的宝藏岛全部切断的 ...

  4. hdu_5293_Tree chain problem(DFS序+树形DP+LCA)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5293 被这题打蹦了,看着题解写的,很是爆炸,确实想不到,我用的DFS序+LCA+树形DP,当然也可以写 ...

  5. 【bzoj4182】Shopping 树的点分治+dfs序+背包dp

    题目描述 给出一棵 $n$ 个点的树,每个点有物品重量 $w$ .体积 $c$ 和数目 $d$ .要求选出一个连通子图,使得总体积不超过背包容量 $m$ ,且总重量最大.求这个最大总重量. 输入 输入 ...

  6. 51 nod 1681 公共祖先 (主席树+dfs序)

    1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题   有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另 ...

  7. Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

    题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB    总提交次数:196   AC次数:65   平均分: ...

  8. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  9. 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序

    题目大意 ​ Bob有一棵\(n\)个点的有根树,其中\(1\)号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜 ...

  10. 【bzoj4817】树点涂色 LCT+线段树+dfs序

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

随机推荐

  1. Bootstrap历练实例:默认的媒体对象

    Bootstrap 多媒体对象(Media Object) 本章我们将讲解 Bootstrap 中的多媒体对象(Media Object).这些抽象的对象样式用于创建各种类型的组件(比如:博客评论), ...

  2. bootstrap 超大屏幕(Jumbotron)

    本章将讲解Bootstrap的一个特性:超大屏幕(Jumbonron),顾名思义该组件可以增加标题的大小,并为登录页面的内容添加更多的外边矩. 使用超大屏幕的步骤如下: 1.创建一个还有class.j ...

  3. bash编程之循环控制:

    bash编程之循环控制: for varName in LIST; do 循环体 done   while CONDITION; do 循环体 done   until CONDITION; do 循 ...

  4. char与varchar的区别与联系

    char是字节类型,varcahr是字符类型 1.char(20) 存放的是字节,utf-8中文字符占三个字节,GB18030兼容GBK兼容GB2312中文字符占两个字节,ISO8859-1是拉丁字符 ...

  5. VMware安装Ubuntu配置NAT模式下静态IP,解决访问外网问题

    安装好VMware后,打开网络连接可以看到有VMware Network Adapter VMnet1和VMware Network Adapter VMnet8两个网络适配器,VMnet1是针对桥接 ...

  6. day12-迭代器

    迭代器的概念 内部含有_next_和_iter_方法的就是迭代器. 可以被for循环的都是可迭代的,只有是可迭代对象,才能用for循环. 可迭代的内部都有_iter_方法——可迭代协议. 只要是迭代器 ...

  7. MySQL练习50题

    介绍一个学习SQL的网站:https://sqlbolt.com/ 习题来源于网络,SQL语句是自己的练习答案,部分参考了网络上的答案. 花了一晚上的时间做完,个人认为其中的难点有:分组提取前几名的数 ...

  8. nordic芯片开发——烧写方法记录

    在开发nordic芯片的时候,分为存外设开发和结合softdevice开发,另外还有结合mbr的开发(这个暂时没有深究)在裸机开发的时候,sdk里面称为blank,把芯片的程序erase之后,直接下载 ...

  9. spring关于@Autowired和@Qualifier的使用

    // package com.jhc.model; import org.springframework.stereotype.Component; @Component public interfa ...

  10. Linux学习-Linux 主机上的用户讯息传递

    查询使用者: w, who, last, lastlog 如果你想要知道目前已登入在系统上面的用户呢?可以透过 w 或 who 来查询喔!如下范例所示: [root@study ~]# w 01:49 ...