您的位置:首页 > 其它

BZOJ2286:[SDOI2011]消耗战——题解

2018-01-12 17:16 295 查看

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

http://www.lydsy.com/JudgeOnline/problem.php?id=2286

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

UPD 18/5/3:我终于懂虚树啦!以及美化代码。

显然是虚树啊……然而我还是不懂虚树怎么建的……

但是dp十分的简单,就是在虚树上dp[i]表示从i以下的资源节点都到不了i的最小费用。

设u为v的儿子,则:

当u有资源的时候,显然是从v到u的路径中挑一条最小费用的路径割掉即可。

当u没有资源的时候,要么将u往下的资源节点和u断开联系(即将dp[v]+=dp[u]),要么选择从v到u的路径中挑一条最小费用的路径割掉。

 

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<cmath>
#include<stack>
using namespace std;
typedef long long ll;
const int N=250005,B=18;
const int INF=0x7fffffff;
inline int read(){
int X=0,w=0;char ch=0;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
struct node{
int w,to,nxt;
}e[2*N];
int n,m,cnt,head
,dep
;
int anc
[B+4],val
[B+4];
int aux
,pos
,stk
,tot;
int fa_aux
,tmp
,num,top;
bool vis
;
ll dp
;
inline bool cmp(int a,int b){return pos[a]<pos[b];}
inline void add(int u,int v,int w){
e[++cnt].to=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
}
void dfs(int u){
pos[u]=++tot;dep[u]=dep[anc[u][0]]+1;
for(int i=1;i<=B;i++){
anc[u][i]=anc[anc[u][i-1]][i-1];
val[u][i]=min(val[u][i-1],val[anc[u][i-1]][i-1]);
}
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to,w=e[i].w;
if(anc[u][0]!=v){
anc[v][0]=u;val[v][0]=w;
dfs(v);
}
}
}
inline int LCA(int i,int j){
if(dep[i]<dep[j])swap(i,j);
for(int k=B;k>=0;--k)
if(dep[anc[i][k]]>=dep[j])i=anc[i][k];
if(i==j)return i;
for(int k=B;k>=0;--k)
if(anc[i][k]!=anc[j][k])
i=anc[i][k],j=anc[j][k];
return anc[i][0];
}
void build(int t){
sort(aux+1,aux+t+1,cmp);
num=t;stk[top=0]=0;
for(int i=1;i<=t;i++){
int u=aux[i];
if(!top)fa_aux[u]=0,stk[++top]=u;
else{
int lca=LCA(u,stk[top]);
while(dep[stk[top]]>dep[lca]){
if(dep[stk[top-1]]<=dep[lca])
fa_aux[stk[top]]=lca;
top--;
}
if(stk[top]!=lca){
fa_aux[lca]=stk[top];
stk[++top]=lca;
aux[++num]=lca;
}
fa_aux[u]=lca;
stk[++top]=u;
}
}
sort(aux+1,aux+num+1,cmp);
}
inline ll cut(int u,int v){
int res=INF;
for(int i=B;i>=0;i--)
if(dep[anc[u][i]]>=dep[v]){
res=min(res,val[u][i]);
u=anc[u][i];
}
return res;
}
void solve(){
for(int i=1;i<=num;i++)dp[aux[i]]=0;
for(int i=num;i>=1;i--){
int u=aux[i],v=fa_aux[u];
if(!vis[u])
dp[v]+=min(dp[u],cut(u,v));
else dp[v]+=cut(u,v);
}
}
int main(){
n=read();
for(int i=1;i<n;i++){
int u=read(),v=read(),w=read();
add(u,v,w);add(v,u,w);
}
dfs(1);
m=read();
while(m--){
int t=read();
for(int i=1;i<=t;i++){
int u=read();
aux[i]=tmp[i]=u;vis[u]=1;
}
aux[++t]=1;
build(t);solve();
printf("%lld\n",dp[1]);
for(int i=1;i<=t;i++)vis[tmp[i]]=0;
}
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: