在一场战争中,战场由 nnn 个岛屿和 n−1n-1n−1 个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为 111 的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他 kkk 个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。
侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到 111 号岛屿上)。不过侦查部门还发现了这台机器只能够使用 mmm 次,所以我们只需要把每次任务完成即可。
第一行一个整数 nnn,表示岛屿数量。
接下来 n−1n-1n−1 行,每行三个整数 u,v,wu,v,wu,v,w ,表示 uuu 号岛屿和 vvv 号岛屿由一条代价为 www 的桥梁直接相连。
第 n+1n+1n+1 行,一个整数 mmm ,代表敌方机器能使用的次数。
接下来 mmm 行,第 iii 行一个整数 kik_iki ,代表第 iii 次后,有 kik_iki 个岛屿资源丰富。接下来 kik_iki 个整数 h1,h2,...,hkih_1,h_2,..., h_{k_i}h1,h2,...,hki ,表示资源丰富岛屿的编号。
输出共 mmm 行,表示每次任务的最小代价。
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
12
32
22
#include
#define int long long
using namespace std;
const int N=1e6+5;
int h[N],h1[N],to[N],to1[N],w[N],w1[N],ne[N],ne1[N],tot,tot1;
int fa[N],dfn[N],top[N],son[N],s[N],cnt,de[N],sta[N];
int num[N],zhi[N],shu[N],sum[N*2],n,q,ru[N],minnd,ans[N];
bool vis[N];
set<int>s1;
bool cmp(int aa,int bb)
{
return dfn[aa]<dfn[bb];
}
void add(int a,int b,int c)
{
tot++;
ne[tot]=h[a];
h[a]=tot;
to[tot]=b;
w[tot]=c;
}
void add1(int a,int b,int c)
{
tot1++;
ne1[tot1]=h1[a];
h1[a]=tot1;
to1[tot1]=b;
w1[tot1]=c;
}
void dfs1(int u,int f)
{
s[u]=1;
de[u]=de[f]+1;
dfn[u]=++cnt;
fa[u]=f;
for(int i=h[u];i;i=ne[i])
{
int j=to[i];
if(j!=f)
{
num[j]=w[i];
dfs1(j,u);
s[u]+=s[j];
if(s[son[u]]<s[j])
son[u]=j;
}
}
}
void dfs2(int u)
{
if(son[u])
{
top[son[u]]=top[u];
zhi[son[u]]=++zhi[0];
shu[zhi[0]]=son[u];
dfs2(son[u]);
}
for(int i=h[u];i;i=ne[i])
{
int j=to[i];
if(!top[j])
{
top[j]=j;
zhi[j]=++zhi[0];
shu[zhi[0]]=j;
dfs2(j);
}
}
}
int qiu(int k,int l,int r,int nowl,int nowr)
{
if(nowr<l||nowl>r)return 1e12;
if(nowl>=l&&nowr<=r)
return sum[k];
int mid=nowl+nowr>>1;
int minn=1e12;
if(mid>=nowl)minn=min(minn,qiu(k<<1,l,r,nowl,mid));
if(mid<nowr)minn=min(minn,qiu((k<<1)+1,l,r,mid+1,nowr));
return minn;
}
void build(int k,int l,int r)
{
int mid=l+r>>1;
if(l==r)
{
sum[k]=num[shu[l]];
return;
}
build(k<<1,l,mid);
build((k<<1)+1,mid+1,r);
sum[k]=min(sum[k<<1],sum[(k<<1)+1]);
}
int find(int x,int y)
{
int fx=top[x];
int fy=top[y];
minnd=1e12;
while(fx!=fy)
{
if(de[fx]<de[fy])
swap(fx,fy),swap(x,y);
minnd=min(minnd,qiu(1,zhi[fx],zhi[x],1,zhi[0]));
x=fa[fx];fx=top[x];
}
if(de[x]>de[y])swap(x,y);
minnd=min(minnd,qiu(1,zhi[x]+1,zhi[y],1,zhi[0]));
return x;
}
void dp(int u)
{
ans[u]=0;
for(int i=h1[u];i;i=ne1[i])
{
int j=to1[i];
dp(j);
if(s1.count(j))ans[u]+=w1[i];
else
ans[u]+=min(ans[j],w1[i]);
}
}
signed main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n;
int a,b,c;
for(int i=1;i<n;i++)
{
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
// memset(sum,1e12,sizeof(sum));
dfs1(1,0);
zhi[0]=zhi[1]=shu[1]=top[1]=1;
dfs2(1);
build(1,1,zhi[0]);
cin>>q;
while(q--)
{
s1.clear();
tot1=0;
int kk;
cin>>kk;
for(int i=1;i<=kk;i++)
{
cin>>ru[i];
s1.insert(ru[i]);
}
sort(ru+1,ru+1+kk,cmp);
int be=1;
sta[1]=1;
h1[1]=0;
for(int i=1;i<=kk;i++)
{
int lc=find(sta[be],ru[i]);
if(lc!=sta[be])
{
while(dfn[lc]<dfn[sta[be-1]])
{
find(sta[be],sta[be-1]);
add1(sta[be-1],sta[be],minnd);
be--;
}
if(dfn[sta[be-1]]<dfn[lc])
{
find(sta[be],lc);
h1[lc]=0;
add1(lc,sta[be],minnd);
// cout<
sta[be]=lc;
}
else
{
find(sta[be],lc);
add1(lc,sta[be],minnd);
// cout<
be--;
}
}
h1[ru[i]]=0;
sta[++be]=ru[i];
// cout<
}
while(be>1)
{
find(sta[be-1],sta[be]);
add1(sta[be-1],sta[be],minnd);
be--;
}
// memset(,0,sizeof(dp));
// for(int i=h1[1];i;i=ne1[i])
// cout<<1<<" "<
// cout<<1<<" "<
// cout<<24<
dp(1);
cout<<ans[1]<<'\n';
}
// for(int i=1;i<=n*2;i++)
// cout<
return 0;
}