【题解】P2495 【模板】虚树 / [SDOI2011] 消耗战

P2495】题解

一:【题意】

  • 给定一张带边权图
  • 每次给出关键点,求切断所有关键点与1联系的最小花费

二:【解法】

建虚树,预处理每个点到根的边的最小值dis,跑树形dp
dp[u]:切断u子树(不包含u)关键点与1联系的最小花费
枚举u的子节点v
if(v是关键点) dp[u]+=dis[v]
else dp[u]+=min(dis[v],dp[v])

三:【代码】

#include<bits/stdc++.h>
#define Pair pair<int,int>
#define w first
#define to second
#define inf 2e9
using namespace std;
typedef long long LL;
const int N=2.5e5+10;
vector<Pair> mp[N];
int siz[N];
int fa[N];
int dep[N];
int son[N];
void Son(int u,int pa){
	siz[u]=1;
	dep[u]=dep[pa]+1;
	fa[u]=pa;
	for(auto e:mp[u]){
		int v=e.to;
		if(v==pa) continue;
		Son(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]) son[u]=v;
	}
}
int top[N],dfn[N],cnt;
void Line(int u,int tp){
	dfn[u]=++cnt;
	top[u]=tp;
	if(!son[u]) return ;
	Line(son[u],tp);
	for(auto e:mp[u]){
		int v=e.to;
		if(v==fa[u]||v==son[u]) continue;
		Line(v,v);
	}
}
int LCA(int a,int b){
	while(top[a]!=top[b]){
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return a;
}
LL dis[N];
void Min(int u,int fa){
	for(auto e:mp[u]){
		int v=e.to,w=e.w;
		if(v==fa) continue;
		dis[v]=min(dis[u],(LL)w);
		Min(v,u);
	}
}

int im[N];
vector<int> st;
bool cmp(int x,int y){
	return dfn[x]<dfn[y];
}
vector<int> tmp[N];
void Build(){
	sort(st.begin(),st.end(),cmp);
	int len=st.size();
	for(int i=0;i<len-1;i++) st.push_back(LCA(st[i],st[i+1]));
	
	sort(st.begin(),st.end(),cmp);
	st.erase(unique(st.begin(),st.end()),st.end());
	for(int i=0;i<st.size()-1;i++) tmp[LCA(st[i],st[i+1])].push_back(st[i+1]);
}
LL Dp(int u,int fa){
	LL sum=0;
	for(auto v:tmp[u]){
		if(v==fa) continue;
		if(im[v]) sum+=dis[v];
		else sum+=min(dis[v],Dp(v,u));
	}
	return sum;
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int n;cin>>n;
	for(int i=1;i<=n;i++) dis[i]=inf;
	for(int i=1;i<n;i++){
		int a,b,c;cin>>a>>b>>c;
		mp[a].push_back({c,b});
		mp[b].push_back({c,a});
	}
	Son(1,1);
	Line(1,1);
	Min(1,1);
	int m;cin>>m;
	while(m--){
		int len;cin>>len;
		for(int i=1;i<=len;i++){
			int k;cin>>k;
			st.push_back(k);
			im[k]=1;
		}
		st.push_back(1);
		Build();
		cout<<Dp(1,1)<<"\n";
		for(auto u:st){
			tmp[u].clear();
			im[u]=0;
		}
		st.clear();
	}
	return 0;
}
posted @ 2025-12-15 17:59  Ming3398  阅读(1)  评论(0)    收藏  举报