bzoj2286
很明显,20%=mincut 40%=每次暴力树形dp
那么正解是什么呢?不难发现∑ki<=500000,也就是每次询问的复杂度都要跟k有关
从树形dp工作的角度来看,确实有很多点我们根本就没必要访问,我们设每次要割断的岛屿为关键点
这里引入了一个新的东西叫做虚树,简单来说就是把树上没用的点去掉收缩成一棵树
具体来说,如果一个点的子树中至多只有一棵子树包含关键点,那么这个点就可以删掉
也就是说只有关键点和他们的lca会被保留下来就行了,证明总点数<=2*k-1
那么怎么构建虚树?我们先按dfs序排序,然后按这个顺序不断加点维护虚树上最新的路径
感觉建树的方法只可意会不可言传,具体见代码吧……
type node=record
len,po,next:longint;
end; var e:array[..] of node;
anc:array[..,..] of longint;
b,d,p,c,fa,st,a:array[..] of longint;
f:array[..] of int64;
v:array[..] of boolean;
w,s,m,h,t,n,len,i,x,y,z:longint; function min(a,b:longint):longint;
begin
if a>b then exit(b) else exit(a);
end; procedure swap(var a,b:longint);
var c:longint;
begin
c:=a;
a:=b;
b:=c;
end; procedure sort(l,r: longint);
var i,j,x:longint;
begin
i:=l;
j:=r;
x:=b[a[(l+r) shr ]];
repeat
while b[a[i]]<x do inc(i);
while x<b[a[j]] do dec(j);
if not(i>j) then
begin
swap(a[i],a[j]);
inc(i);
j:=j-;
end;
until i>j;
if l<j then sort(l,j);
if i<r then sort(i,r);
end; procedure add(x,y,z:longint);
begin
inc(len);
e[len].po:=y;
e[len].len:=z;
e[len].next:=p[x];
p[x]:=len;
end; procedure dfs(x:longint);
var i,y:longint;
begin
inc(t);
b[x]:=t; //dfs序
for i:= to h do
begin
y:=anc[x,i-];
if y<> then anc[x,i]:=anc[y,i-]
else break;
end;
i:=p[x];
while i<> do
begin
y:=e[i].po;
if fa[x]<>y then
begin
fa[y]:=x;
anc[y,]:=x;
c[y]:=min(c[x],e[i].len); //c[]表示把这个点和根节点割开最小代价
d[y]:=d[x]+;
dfs(y);
end;
i:=e[i].next;
end;
end; function lca(x,y:longint):longint;
var i,p:longint;
begin
if d[x]<d[y] then swap(x,y);
p:=trunc(ln(d[x])/ln());
if d[x]>d[y] then
for i:=p downto do
if d[x]- shl i>=d[y] then x:=anc[x,i];
if x=y then exit(x);
for i:=p downto do
if (anc[y,i]<>anc[x,i]) then
begin
x:=anc[x,i];
y:=anc[y,i];
end;
exit(fa[x]);
end; procedure dp(x:longint); //dp过程很简单
var i,y:longint;
s:int64;
begin
if x= then f[]:=*
else f[x]:=c[x];
i:=p[x];
s:=;
while i<> do
begin
y:=e[i].po;
dp(y);
s:=s+f[y];
i:=e[i].next;
end;
p[x]:=;
if (s<>) then
if f[x]>s then f[x]:=s;
end; begin
readln(n);
h:=trunc(ln(n)/ln());
for i:= to n- do
begin
readln(x,y,z);
add(x,y,z);
add(y,x,z);
end;
c[]:=;
dfs();
readln(m);
fillchar(p,sizeof(p),);
while m> do
begin
dec(m);
read(s);
for i:= to s do
read(a[i]); sort(,s);
w:=;
for i:= to s do
if lca(a[w],a[i])<>a[w] then //这里一点点优化,如果存在祖先关系的关键点,肯定割祖先以上的边
begin
inc(w);
a[w]:=a[i];
end;
len:=;
st[]:=;
t:=;
for i:= to w do
begin
x:=a[i];
z:=lca(x,st[t]);
while d[z]<d[st[t]] do //这里画个图比较好理解,类似一个新路径和原来维护的路径的一个分叉
begin
if d[z]>=d[st[t-]] then
begin
add(z,st[t],);
dec(t);
if st[t]<>z then
begin
inc(t);
st[t]:=z;
end;
break;
end;
add(st[t-],st[t],); //把原来分叉的那段建出来
dec(t);
end;
if st[t]<>x then
begin
inc(t);
st[t]:=x;
end;
end;
while t> do //把维护的路径建出来
begin
add(st[t-],st[t],);
dec(t);
end;
dp();
writeln(f[]);
end;
end.
bzoj2286的更多相关文章
- 【bzoj2286】 消耗战
http://www.lydsy.com/JudgeOnline/problem.php?id=2286 (题目链接) 一个小小的细节,WA了一天,欲哭无泪了.. 题意 给出一个n个节点的带权树,总共 ...
- [bzoj2286][Sdoi 2011]消耗战
[bzoj2286]消耗战 标签: 虚树 DP 题目链接 题解 很容易找出\(O(mn)\)的做法. 只需要每次都dp一遍. 但是m和n是同阶的,所以这样肯定会T的. 注意到dp的时候有很多节点是不需 ...
- 【BZOJ2286】消耗战(虚树,动态规划)
[BZOJ2286]消耗战(虚树,动态规划) 题面 BZOJ Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总 ...
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4998 Solved: 1867[Submit][Statu ...
- 【BZOJ2286】[Sdoi2011]消耗战 虚树
[BZOJ2286][Sdoi2011]消耗战 Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的 ...
- 【BZOJ2286】消耗战(虚树,DFS序,树形DP)
题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权. 共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价. ...
- 虚树+【BZOJ2286】【SDOI2011】消耗战(虚树)(DP)
先看一道题: [BZOJ2286][SDOI2011]消耗战 Description 在一场战争中,战场由n个岛屿和n−1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总 ...
- [BZOJ2286][Sdoi2011]消耗战(虚树上DP)
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6457 Solved: 2533[Submit][Statu ...
- 【学习笔记】虚树复习记(BZOJ2286 SDOI2011 消耗战)
想写战略游戏却想不起来虚树T^T 所以就有了这篇复习记QwQ ——简介!—— 我们在处理树上问题的时候,dfs是一个常用手段,但是我们发现,如果一棵树上只有一部分关键点,每次dfs需要访问好多不是关键 ...
- bzoj2286 消耗战
还是虚树的题目啊... 如果只有一个询问,我们这么考虑,可以设dp[x]为只删除x子树内和x到父亲的边,使得x这棵子树内的能源岛屿都与x的父亲不连通的最小花费. 这样如果x本身是能源岛屿,那么dp[x ...
随机推荐
- HDOJ 1042 N! -- 大数运算
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1042 Problem Description Given an integer N(0 ≤ N ≤ 1 ...
- 九度OJ 1510 替换空格
题目地址:http://ac.jobdu.com/problem.php?pid=1510 题目描述: 请实现一个函数,将一个字符串中的空格替换成"%20".例如,当字符串为We ...
- mysql时间与日期函数
返回日期相关的 Now() || CURRENT_TIMESTAMP();返回当前时间 to_days(date) 返回日期date是西元0年至今多少天(不计算1582年以前) 转换为天数 date是 ...
- Android开发系列之ListView
上篇博客解决了Android客户端通过WebService与服务器端程序进行交互的问题,这篇博客重点关注两个问题,一个是Android应用程序如何与本机文件型数据库SQLite进行交互,另一问题则是如 ...
- WCF SOA服务应用
WCF是微软官方推出的一个基于服务的整合框架,它整合了以前的Web Service.MSMQ.Remoting等通信技术,通过灵活的配置,让服务编程更加容易.可扩展.这篇文章主要目的就是带领大家从开发 ...
- NUnit单元测试
单元测试对程序员来说是非常重要的一门技术,但是在实际编程中却往往被程序员所忽视.微软的VS开发工具为我们提供了强大的单元测试环境,在VS当中可以直接对类库项目进行测试,极大的方便了程序员的自我纠错能力 ...
- CentOS 最小化安装后安装桌面
通过yum的方式安装: yum groupinstall -y "Desktop" "Desktop Platform" "Desktop ...
- 基于等待队列及poll机制的按键驱动代码分析和测试代码
按键驱动分析: #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> ...
- C#并行和多线程编程_(1)认识Parallel
Parallel: 英 [ˈpærəlel] 美 [ˈpærəˌlɛl] ,并联的,并行的. 随着多核时代的到来,并行开发越来越展示出它的强大威力!使用并行程序,充分的利用系统资源,提高程序的性 ...
- 导航栏 & 状态栏覆盖
当 automaticallyAdjustsScrollViewInsets 为 YES 时,也是默认行为,表现就比较正常了,和 edgesForExtendedLayout = UIRectEdge ...