[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
Solution
虚树入门题。
注意如果一个点被标记了,它子树下也有被标记的点,下面的点可以删掉,然后dp。
#include<bits/stdc++.h>
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar() ((p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2)?EOF:*p1++)
#endif
namespace fast_IO {
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T> inline void read(T &x) {
x=0;T f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
template <typename T,typename... Args> inline void read(T& x,Args& ...args) {
read(x),read(args...);
}
char buf2[1<<21],a[80];int p,p3=-1;
inline void flush() {fwrite(buf2,1,p3+1,stdout),p3=-1;}
template <typename T> inline void write(T x) {
if(p3>(1<<20)) flush();
if(x<0) buf2[++p3]='-',x=-x;
do {a[++p]=x%10+48;} while(x/=10);
do {buf2[++p3]=a[p];} while(--p);
buf2[++p3]='\n';flush();
}
template <typename T,typename... Args> inline void write(T x,Args ...args) {
write(x),write(args...);
}
}
using fast_IO :: read;
using fast_IO :: write;
using fast_IO :: flush;
#define ll long long
const int maxn = 2.5e5+10;
const int inf = 1e9;
int mn[maxn],dfn[maxn],n,sz[maxn];
ll f[maxn];
struct Normal_Tree {
int head[maxn],tot,dfn_cnt,f[maxn][20],dep[maxn];
struct edge{int to,nxt,w;}e[maxn<<1];
void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
void dfs(int x,int fa) {
dfn[x]=++dfn_cnt;f[x][0]=fa;dep[x]=dep[fa]+1;sz[x]=1;
for(int i=1;i<=17;i++) f[x][i]=f[f[x][i-1]][i-1];
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa) mn[e[i].to]=min(mn[x],e[i].w),dfs(e[i].to,x),sz[x]+=sz[e[i].to];
}
int lca(int x,int y) {
if(dep[x]<dep[y]) swap(x,y);
for(int i=17;~i;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
if(x==y) return x;
for(int i=17;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
}T;
int cmp(int x,int y) {return dfn[x]<dfn[y];}
struct Virtual_Tree {
int head[maxn],tot,sta[maxn],use[maxn],in[maxn],top,used,a[maxn];
struct edge{int to,nxt;}e[maxn<<1];
void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
void ins(int u,int v) {add(u,v),add(v,u);}
void dfs(int x,int fa) {
int bo=1;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa) dfs(e[i].to,x),f[x]+=min((ll)mn[e[i].to],f[e[i].to]),bo=0;
if(bo) f[x]=mn[x];
//printf("Dfs:%d %d\n",x,f[x]);
}
void solve() {
int k;read(k);top=used=0;
for(int i=1;i<=k;i++) read(a[i]);
sort(a+1,a+k+1,cmp);int p=0;
for(int i=1;i<=k;i++)
if(dfn[a[i]]>dfn[in[p]]+sz[in[p]]-1) in[++p]=a[i];
k=p;
sta[++top]=1;use[++used]=1;
for(int i=1;i<=k;i++) {
if(in[i]==1) continue;
int t=T.lca(in[i],sta[top]),pre=-1;
while(dfn[sta[top]]>dfn[t]&&dfn[sta[top]]<dfn[t]+sz[t]) {
if(pre!=-1) ins(sta[top],pre);
pre=sta[top];use[++used]=sta[top];top--;
}
if(pre!=-1) ins(t,pre);
if(sta[top]!=t) sta[++top]=t;
sta[++top]=in[i];
}
int pre=-1;
while(top) {
if(pre!=-1) ins(sta[top],pre);
pre=sta[top],use[++used]=sta[top];top--;
}
dfs(1,0),write(f[1]);
for(int i=1;i<=used;i++) head[use[i]]=0,f[use[i]]=0;
tot=0;
}
}VT;
int main() {
read(n);
for(int i=1,x,y,z;i<n;i++) read(x,y,z),T.ins(x,y,z);
for(int i=1;i<=n;i++) mn[i]=inf,f[i]=0;T.dfs(1,0);mn[1]=0;
int t;read(t);
while(t--) VT.solve();
flush();
return 0;
}