【BZOJ-2286】消耗战 虚树 + 树形DP
2286: [Sdoi2011消耗战
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 2120 Solved: 752
[Submit][Status][Discuss]
Description
Input
第一行一个整数n,代表岛屿数量。
接下来n-1行,每行三个整数u,v,w,代表u号岛屿和v号岛屿由一条代价为c的桥梁直接相连,保证1<=u,v<=n且1<=c<=100000。
第n+1行,一个整数m,代表敌方机器能使用的次数。
接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。
Output
输出有m行,分别代表每次任务的最小代价。
Sample Input
1 5 13
1 9 6
2 1 19
2 4 8
2 3 91
5 6 8
7 5 4
7 8 31
10 7 9
3
2 10 6
4 5 7 8 3
3 9 4 6
Sample Output
32
22
HINT
对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1
Source
Solution
虚树+树形DP
先看虚树...
一点个人的理解:
给定的树上有很多节点比较无用,会影响复杂度,所以我们需要把它们的影响降低,那么我们就建出一棵包含所有特殊点的,以及一些必要的LCA的虚树,使得里面的点数尽量的少
大体的构建需要 栈 + LCA + dfs序
首先对给出的树求出dfs序,然后将给出的特殊点按dfs序从小到大排序;
然后用一个栈去维护,退栈和虚树连边是相结合的,这个栈中元素的意义:当前点在原树中到根的路径上在虚树上的点
排序之后,从左到右加点,假设当前要入栈的节点$x$,与当前栈顶LCA为$y$,当$x$被加入后,栈中所有深度>$y$的点需要退栈,这时候就对应连边
一个栗子(转):
为了方便,假定dfs序和编号是一样的,红色点为特殊点
那么我们模拟一下虚树的构造过程,
首先按照dfs序,我们加入3,此时stack{3}
然后加入5,栈顶为3,它们的LCA为2,这时候开始退栈,发现deep[3]>deep[2]所以把3退栈,这时候2-->3连边
然后2入栈,此时stack{2}
然后5入栈,此时stack{2,5}
然后考虑6,栈顶为5,它们的LCA为2,这时候开始退栈,发现deep[5]>deep[2]那么把5退栈,这时候2-->5连边
然后考虑2入栈,发现栈顶为2,那么2不入栈
然后5入栈,此时stack{2,6}
依次退栈2-->6连边。
大体的建树操作:
bool cmp(int x,int y) {return dfn[x]<dfn[y];}
struct RoadNode{int next,to;}road[MAXN<<];
int last[MAXN],tot;
void AddRoad(int u,int v) {tot++; road[tot].next=last[u]; last[u]=tot; road[tot].to=v;}
void InsertRoad(int u,int v) {if (u==v) return; AddRoad(u,v);}
int a[MAXN],tp,st[MAXN],top;
void MakeTree(int K)
{
tot=;
sort(a+,a+K+,cmp);
tp=; a[++tp]=a[];
for (int i=; i<=K; i++) if (LCA(a[tp],a[i])!=a[tp]) a[++tp]=a[i];
st[++top]=;
for (int i=; i<=tp; i++)
{
int now=a[i],lca=LCA(now,st[top]);
while (top)
{
if (deep[lca]>=deep[st[top-]])
{
InsertRoad(lca,st[top--]);
if (st[top]!=lca) st[++top]=lca;
break;
}
InsertRoad(st[top-],st[top]); top--;
}
if (st[top]!=now) st[++top]=now;
}
while (--top) InsertRoad(st[top],st[top+]);
}
MakeTree
这道题就是建出虚树,然后再虚树上进行DP,这道题是简单DP,就不细说了
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 300010
#define LL long long
int N,M,K;
struct EdgeNode{int next,to,val;}edge[MAXN<<];
int head[MAXN],cnt;
void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].val=w;}
void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);}
int deep[MAXN],dfn[MAXN],father[MAXN][],t;
LL minn[MAXN];
void DFS(int now,int last)
{
dfn[now]=++t;
for (int i=; i<=; i++)
if (deep[now]>=(<<i))
father[now][i]=father[father[now][i-]][i-];
else break;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last)
{
minn[edge[i].to]=min(minn[now],(LL)edge[i].val);
deep[edge[i].to]=deep[now]+;
father[edge[i].to][]=now;
DFS(edge[i].to,now);
}
}
int LCA(int x,int y)
{
if (deep[x]<deep[y]) swap(x,y);
int dd=deep[x]-deep[y];
for (int i=; i<=; i++)
if (dd&(<<i)) x=father[x][i];
for (int i=; i>=; i--)
if (father[x][i]!=father[y][i])
x=father[x][i],y=father[y][i];
if (x==y) return x; else return father[x][];
}
bool cmp(int x,int y) {return dfn[x]<dfn[y];}
struct RoadNode{int next,to;}road[MAXN<<];
int last[MAXN],tot;
void AddRoad(int u,int v) {tot++; road[tot].next=last[u]; last[u]=tot; road[tot].to=v;}
void InsertRoad(int u,int v) {if (u==v) return; AddRoad(u,v);}
int a[MAXN],tp,st[MAXN],top;
void MakeTree(int K)
{
tot=;
sort(a+,a+K+,cmp);
tp=; a[++tp]=a[];
for (int i=; i<=K; i++) if (LCA(a[tp],a[i])!=a[tp]) a[++tp]=a[i];
st[++top]=;
for (int i=; i<=tp; i++)
{
int now=a[i],lca=LCA(now,st[top]);
while (top)
{
if (deep[lca]>=deep[st[top-]])
{
InsertRoad(lca,st[top--]);
if (st[top]!=lca) st[++top]=lca;
break;
}
InsertRoad(st[top-],st[top]); top--;
}
if (st[top]!=now) st[++top]=now;
}
while (--top) InsertRoad(st[top],st[top+]);
}
LL f[MAXN];
void DP(int now)
{
f[now]=minn[now];
LL tmp=;
for (int i=last[now]; i; i=road[i].next)
DP(road[i].to),tmp+=f[road[i].to];
last[now]=;
if (tmp==) f[now]=minn[now]; else f[now]=min(tmp,f[now]);
}
int main()
{
N=read();
for (int x,y,z,i=; i<=N-; i++) x=read(),y=read(),z=read(),InsertEdge(x,y,z);
minn[]=1LL<<;
DFS(,);
M=read();
while (M--)
{
K=read();
for (int i=; i<=K; i++) a[i]=read();
MakeTree(K);
DP();
printf("%lld\n",f[]);
}
return ;
}
【BZOJ-2286】消耗战 虚树 + 树形DP的更多相关文章
- BZOJ 2286 消耗战 (虚树+树形DP)
给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...
- BZOJ.2286.[SDOI2011]消耗战(虚树 树形DP)
题目链接 BZOJ 洛谷P2495 树形DP,对于每棵子树要么逐个删除其中要删除的边,要么直接断连向父节点的边. 如果当前点需要删除,那么直接断不需要再管子树. 复杂度O(m*n). 对于两个要删除的 ...
- BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序
https://www.lydsy.com/JudgeOnline/problem.php?id=2286 wa了两次因为lca犯了zz错误 这道题如果不多次询问的话就是裸dp. 一棵树上多次询问,且 ...
- BZOJ 2286 消耗战 - 虚树 + 树型dp
传送门 题目大意: 每次给出k个特殊点,回答将这些特殊点与根节点断开至少需要多少代价. 题目分析: 虚树入门 + 树型dp: 刚刚学习完虚树(好文),就来这道入门题签个到. 虚树就是将树中的一些关键点 ...
- 【BZOJ2286】【SDOI2011】消耗战 [虚树][树形DP]
消耗战 Time Limit: 20 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1 ...
- BZOJ2286: [Sdoi2011]消耗战(虚树/树形DP)
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5246 Solved: 1978[Submit][Status][Discuss] Descript ...
- bzoj 2286(虚树+树形dp) 虚树模板
树链求并又不会写,学了一发虚树,再也不虚啦~ 2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5002 Sol ...
- BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP+树剖lca
BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的 ...
- 【BZOJ-3572】世界树 虚树 + 树形DP
3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1084 Solved: 611[Submit][Status ...
随机推荐
- JS的递归与TCO尾调用优化
转自:https://segmentfault.com/a/1190000004018047 这两天搜了下JS递归的相关文章, 觉得这篇文章很不错, 就顺手翻译了下,也算给自己做个笔记,题目是我自己加 ...
- ToolkitScriptManager, ScriptManager AjaxControlToolkit 出错
在使用ASP.NET AJAX应用时需添加ToolkitScriptManager或者ScriptManager.如果只是使用updatepanel,两者均可.如果有涉及到AJAX Control T ...
- 笔记 (note)
笔记[问题描述]给定一个长度为m的序列a,下标编号为1~m.序列的每个元素都是1~n的整数.定义序列的代价为m−1 ∑|ai+1-ai| i=1 你现在可以选择两个数x和y,并将序列a中所有的x改成y ...
- hessian学习
hessian是一个采用二进制格式传输的服务框架,相对传统soap web service,更轻量,更快速.官网地址:http://hessian.caucho.com/ 目前已经支持N多语言,包括: ...
- TinyFrame开篇:基于CodeFirst的ORM
前言 做项目的这段时间,由于比较忙,一直没有机会闲下来思考.正好趁目前手头活儿轻松点,就花了一两天时间搭建了一个比较简单的框架,名称暂时就叫做:TinyFrame吧.顾名思义,就是微框架的意思.虽然这 ...
- RMQ(ST算法)
RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列a,回答若干询问RMQ(A,i,j)(i, j<=n),返回数列a中下标在i ...
- 30行代码实现Javascript中的MVC
从09年左右开始,MVC逐渐在前端领域大放异彩,并终于在刚刚过去的2015年随着React Native的推出而迎来大爆发:AngularJS.EmberJS.Backbone.ReactJS.Rio ...
- 又发现个.net framework的坑
请找出这两个方法的区别: http://msdn.microsoft.com/en-us/library/ms584187(v=vs.110).aspx
- redis在window环境下的安装
1.下载客户端文件 地址:https://github.com/dmajkic/redis/downloads 客户端文件目录说明: 2.启动redis服务端 1.在客户端文件目录下新建一个bat文件 ...
- Ueditor 上传图片 如何设置只显示 本地上传
我这个是自问自答,其实很简单.只要按照以下方式修改就可以了. 找到image.html 将以下代码 <div id="tabHeads" class="tabhea ...