【BZOJ2286】[Sdoi2011]消耗战

Description

在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。
侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到1号岛屿上)。不过侦查部门还发现了这台机器只能够使用m次,所以我们只需要把每次任务完成即可。

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

10
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

12
32
22

HINT

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

题解:特地学了一下虚树的造法。

我们将每次给出的所有点,以及他们影响到的所有点(即他们中任意两点的LCA)都拿出来,然后跑个树形DP就行了。这些点形成的东西叫虚树,问题是怎么建呢?

本人naive的做法:将给出的点按dfs序排序,然后求出相邻两点的LCA,显然这些LCA就是所有点对的LCA,所以这说明虚树的大小是O(k)的。然后我们再将这些点按dfs序排序,然后从左到右模拟DFS的过程,如果下一个点再当前点的子树中,则递归下去,否则回溯。

好吧下面说更NB的做法:先按dfs序排序,然后用栈维护当前的一条链(铭记维护的是链!),那么新加入一个点i+1时,先求出i和i+1的lca,找到这个lca在链上的位置,然后将lca下面的链上的点都弹栈(弹栈的时候顺便连边),最后将lca和i+1扔到栈中。具体做法可以看代码,当然最好还是画画图理解一下。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=250010;
typedef long long ll;
int n,m,K,cnt,top;
int to[maxn<<1],next[maxn<<1],val[maxn<<1],head[maxn],fa[20][maxn],Log[maxn],dep[maxn];
int p1[maxn],p2[maxn],vis[maxn],p[maxn],st[maxn];
ll s[maxn];
vector<int> ch[maxn];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
inline void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
inline int MN(int a,int b) {return dep[a]<dep[b]?a:b;}
void dfs(int x)
{
p1[x]=++p2[0];
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[0][x])
dep[to[i]]=dep[x]+1,fa[0][to[i]]=x,s[to[i]]=min(s[x],(ll)val[i]),dfs(to[i]);
p2[x]=p2[0];
}
inline int lca(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
for(int i=Log[dep[a]-dep[b]];i>=0;i--) if(dep[fa[i][a]]>=dep[b]) a=fa[i][a];
if(a==b) return a;
for(int i=Log[dep[a]];i>=0;i--) if(fa[i][a]!=fa[i][b]) a=fa[i][a],b=fa[i][b];
return fa[0][a];
}
bool cmp(int a,int b)
{
return p1[a]<p1[b];
}
inline void Add(int a,int b)
{
if(b) ch[a].push_back(b);
}
ll solve(int x)
{
ll tmp=0;
for(int i=0;i<(int)ch[x].size();i++) tmp+=solve(ch[x][i]);
ch[x].clear();
if(!vis[x]) tmp=min(tmp,s[x]);
else tmp=s[x];
return tmp;
}
int main()
{
n=rd();
int i,j,a,b,c;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
dep[1]=1,s[1]=1ll<<60,dfs(1);
for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<=n;j++) for(i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]];
m=rd();
for(i=1;i<=m;i++)
{
K=rd();
for(j=1;j<=K;j++) p[j]=rd(),vis[p[j]]=1;
sort(p+1,p+K+1,cmp);
st[top=1]=p[1];
for(j=2;j<=K;j++)
{
a=p[j],b=lca(st[top],a),c=0;
while(top&&dep[st[top]]>dep[b]) Add(st[top],c),c=st[top--];
if(st[top]==b) Add(st[top],c);
if(dep[st[top]]<dep[b]) Add(b,c),st[++top]=b;
st[++top]=a;
}
while(top>1) Add(st[top-1],st[top]),top--;
a=st[1];
printf("%lld\n",solve(a));
for(j=1;j<=K;j++) vis[p[j]]=0;
}
return 0;
}//10 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

【BZOJ2286】[Sdoi2011]消耗战 虚树的更多相关文章

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

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

  2. bzoj2286: [Sdoi2011]消耗战 虚树

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

  3. BZOJ2286: [Sdoi2011]消耗战(虚树/树形DP)

    Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5246  Solved: 1978[Submit][Status][Discuss] Descript ...

  4. 【BZOJ-2286】消耗战 虚树 + 树形DP

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

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

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

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

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

  7. 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP

    [题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...

  8. [SDOI2011]消耗战(虚树+树形动规)

    虚树dp 虚树的主要思想: 不遍历没用的的节点以及没用的子树,从而使复杂度降低到\(\sum\limits k\)(k为询问的节点的总数). 所以怎么办: 只把询问节点和其LCA放入询问的数组中. 1 ...

  9. bzoj 2286(洛谷 2495) [Sdoi2011]消耗战——虚树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2286 https://www.luogu.org/problemnew/show/P2495 ...

随机推荐

  1. 工作笔记4.struts2上传文件到server

    本文介绍两种:上传文件到server的方式   一种是提交Form表单:还有一种是ajaxfileupload异步上传. 一.JSP中:     1.提交Form表单 为了能完毕文件上传,我们应该将这 ...

  2. windows盘符操作

    subst subst x: /d subst y: e:\

  3. Openfiler 之Linux 安装ISCSI initiator和自动挂载

    OPENFILER做TARGET,RED HAT做客户端,如果默认没有安装ISCSI initiator的话,可以在光盘上找到RPM包直接安装.service iscsi start,启动服务,ser ...

  4. 一个下载git库代码的脚本

    由于每日构建需求, 须要用脚本下载代码, 实现自己主动化编译, 这个脚本是整个系统的一小块功能 #!/bin/bash #@author Liuyang #@date 2015-06-23 funct ...

  5. Function.prototype.bind、call与apply方法简介

    前言 前段时间面试遇见一题,题目内容大概是 function Parent() { this.prop = 'parent'; } Parent.prototype.get = function() ...

  6. 【MyBatis学习05】SqlMapConfig.xml文件中的配置总结

    经过上两篇博文的总结,对mybatis中的dao开发方法和流程基本掌握了,这一节主要来总结一下mybatis中的全局配置文件SqlMapConfig.xml在开发中的一些常用配置,首先看一下该全局配置 ...

  7. Rest API By JAX-RS 实现接口发布

    原文地址:http://www.cnblogs.com/oopsguy/p/7503589.html JAX-RS 我们在 JAX-RS 示例中使用相同的模型和 DAO,我们所需要做的只有更改 Sto ...

  8. margin: 0px auto; center 行类 块级

    <html> <head> <title> biaoti </title> </head> <body style="bor ...

  9. net.reflector8.5.0.179过了试用期,要求输入序列号怎么办 注册机 破解

    去网上搜索“reflector keygen注册机下载”,随便找一个版本下载(如果你之前下载的软件自带有“Keygen.exe”注册机的话,直接用自带的注册机就可以了)1.断开网络2.下载安装原程序, ...

  10. Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建胜过Apache十倍的Web服务器(第6版)(转)

    转自:http://blog.s135.com/nginx_php_v6/] 前言:本文是我撰写的关于搭建“Nginx + PHP(FastCGI)”Web服务器的第6篇文章.本系列文章作为国内最早详 ...