题目描述
在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。
侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到1号岛屿上)。不过侦查部门还发现了这台机器只能够使用m次,所以我们只需要把每次任务完成即可。
输入输出格式
输入格式:
第一行一个整数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,表示资源丰富岛屿的编号。
输出格式:
输出有m行,分别代表每次任务的最小代价。
————
抄个模板就能用的东西,不过还是有一定代码量的,需要预处理LCA查询的东西以及题目查询所需要的。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=250000+15;
const int inf=0x3f3f3f3f;
int n,m;
struct edge{
int to,nxt,len;
}e[maxn],xe[maxn];
int head[maxn],xhead[maxn];
int tot,xtot;
void adde(int u,int v,int l){
e[tot].to=v;
e[tot].len=l;
e[tot].nxt=head[u];
head[u]=tot++;
}
void xadde(int u,int v,int l){
xe[xtot].to=v;
xe[xtot].len=l;
xe[xtot].nxt=xhead[u];
xhead[u]=xtot++;
}
int dep[maxn],dfn[maxn];
int w[maxn][19];
int fa[maxn][19];
int dfs_clock;
void dfs(int u,int ff,int dd=0){
dfn[u]=++dfs_clock;
dep[u]=dd;
fa[u][0]=ff;
for(int i=1;i<=18;i++){
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].to;
if(v==ff)continue;
int len=e[i].len;
w[v][0]=len;
dfs(v,u,dd+1);
}
}
void init(){
for(int j=1;j<=18;j++){
for(int i=1;i<=n;i++){
fa[i][j]=fa[fa[i][j-1]][j-1];
w[i][j]=min(w[i][j-1],w[fa[i][j-1]][j-1]);
}
}
}
int LCA(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=18;i>=0;i--){
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
}
if(x==y)return x;
for(int i=18;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i];y=fa[y][i];
}
}
return fa[x][0];
}
int getw(int rt,int x){
int res=inf;
for(int i=18;i>=0;i--){
if(dep[fa[x][i]]>dep[rt]){
res=min(res,w[x][i]);
x=fa[x][i];
}
}
return min(res,w[x][0]);
}
vector<int> req;
vector<int> treenode;
bool cmp(int a,int b){
return dfn[a]<dfn[b];
}
int sta[maxn];
int top;
void build_tree(){
top=0;
for(auto u:req){
treenode.pb(u);
if(top==0){
sta[++top]=u;
continue;
}
int lca=LCA(sta[top],u);
treenode.pb(lca);
while(top>1&&dep[sta[top-1]]>dep[lca]){
xadde(sta[top-1],sta[top],getw(sta[top-1],sta[top]));
top--;
}
if(dep[lca]<dep[sta[top]]){
xadde(lca,sta[top],getw(lca,sta[top]));
top--;
}
if(!top||dep[sta[top]]<dep[lca])sta[++top]=lca;
sta[++top]=u;
}
while(top>1){
xadde(sta[top-1],sta[top],getw(sta[top-1],sta[top]));
top--;
}
}
bool del[maxn];
ll DP(int u,int fa){
if(del[u])return inf;
ll ret=0;
for(int i=xhead[u];i!=-1;i=xe[i].nxt){
int v=xe[i].to;
if(v==fa)continue;
ll len=xe[i].len;
ret+=min(len,DP(v,u));
}
return ret;
}
void work(){
build_tree();
printf("%lld\n",DP(1,1));
}
int main(){
memset(head,-1,sizeof(head));
memset(xhead,-1,sizeof(xhead));
tot=0;
scanf("%d",&n);
for(int i=1,a,b,c;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
adde(a,b,c);adde(b,a,c);
}
dfs(1,1);
init();
scanf("%d",&m);
for(int i=0,k,a;i<m;i++){
req.clear();
scanf("%d",&k);
for(int j=0;j<k;j++){
scanf("%d",&a);
req.pb(a);
del[a]=1;
}
req.pb(1);
sort(req.begin(),req.end(),cmp);
work();
for(auto v:treenode){
xhead[v]=-1;
}
for(auto v:req)del[v]=0;
treenode.clear();
xtot=0;
}
return 0;
}