【BZOJ2286】消耗战(虚树,DFS序,树形DP)
题意:一棵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)的更多相关文章
- 【BZOJ】3991: [SDOI2015]寻宝游戏 虚树+DFS序+set
[题意]给定n个点的带边权树,对于树上存在的若干特殊点,要求任选一个点开始将所有特殊点走遍后返回.现在初始没有特殊点,m次操作每次增加或减少一个特殊点,求每次操作后的总代价.n,m<=10^5. ...
- [JSOI2016]最佳团体 DFS序/树形DP
题目 洛谷 P4322 [JSOI2016]最佳团体 Description 茜茜的舞蹈团队一共有\(N\)名候选人,这些候选人从\(1\)到\(N\)编号.方便起见,茜茜的编号是\(0\)号.每个候 ...
- [SDOI2011][bzoj2286] 消耗战 [虚树+dp]
题面: 传送门 思路: 看到所有询问中的点数总和是十万级别的,就想到用虚树~\(≧▽≦)/~啦 首先,树形dp应该是很明显可以看出来的: 设dp[u]表示以u为根的子树(不包括u)中的宝藏岛全部切断的 ...
- hdu_5293_Tree chain problem(DFS序+树形DP+LCA)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5293 被这题打蹦了,看着题解写的,很是爆炸,确实想不到,我用的DFS序+LCA+树形DP,当然也可以写 ...
- 【bzoj4182】Shopping 树的点分治+dfs序+背包dp
题目描述 给出一棵 $n$ 个点的树,每个点有物品重量 $w$ .体积 $c$ 和数目 $d$ .要求选出一个连通子图,使得总体积不超过背包容量 $m$ ,且总重量最大.求这个最大总重量. 输入 输入 ...
- 51 nod 1681 公共祖先 (主席树+dfs序)
1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另 ...
- Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序
题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s 内存限制:512.0MB 总提交次数:196 AC次数:65 平均分: ...
- BZOJ_3252_攻略_线段树+dfs序
BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...
- 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序
题目大意 Bob有一棵\(n\)个点的有根树,其中\(1\)号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜 ...
- 【bzoj4817】树点涂色 LCT+线段树+dfs序
Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...
随机推荐
- c#和Java中的抽象类
应用场景:当父类中的方法不知道如何去实现的时候,可以考虑将父类写成抽象类,将方法写成抽象方法. 比如:描述一个图形.圆形. 矩形三个类.不管哪种图形都会具备计算面积与周长的行为,但是每种图形计算的方式 ...
- python - 辨识alert、window以及操作
selenium之 辨识alert.window以及操作 原创 2016年08月24日 11:01:04 4820 0 2 更多关于python selenium的文章,请关注我的专栏:Python ...
- MySQL Innodb表空间不足的处理方法
官方给出的解决方案: 添加和删除 InnoDB 数据和日志文件 这一节描述在InnoDB表空间耗尽空间之时,或者你想要改变日志文件大小之时,你可以做的一些事情. 最简单的,增加InnoDB表空间大小的 ...
- iOS 通过storyboard设置UIView或者其他layer图层的圆角
通常我们给Button或者UIView添加圆角是通过如下代码进行实现的 self.button.layer.cornerRadius=10; 但是如果你是使用的故事版或者xib进行设计视图的话,实际上 ...
- unity3d sqlite数据库的读写方法
首先,我们要从unity的安装路径中复制mono.data.sqlite.dll和sqlite3.dll两个动态链接库到untiy的plugins目录下,如下图所示: 使用navicat for sq ...
- git使用stash存储相关操作
git stash 将当前修改存储起来 git stash apply 恢复最近一次存储 git stash apply stash@{2} 恢复某一次存储 git stash list 查看存储列 ...
- 天问之Linux内核中的不明白的地方
1. Linux 0.11\linux\kernel\exit.c 文件中, 无论是send_sig()函数还是kill_session()函数中,凡是涉及到发送信号的地方,都是直接 (*p)- ...
- luogu1233 木棍加工
先排个序然后做最长上升子序列就行了. #include <algorithm> #include <iostream> #include <cstdio> usin ...
- Linux下配置LAMP环境
先准备相关软件,并确保服务器已经安装了gcc,gcc-c++,make三个软件,以便后续编译过程. 首先安装, libxml2 ftp://xmlsoft.org/libxml2/ 下载最新版本(我的 ...
- 电商平台API接口