学习:chenhuan001
模板借鉴:自为风月马前卒
虚树模板题:P2495 [SDOI2011]消耗战
思路:裸虚树题,建好虚树后直接在虚树上树形dp即可。
#include<bits/stdc++.h>
#define ll long long
#define P pair<int,int>
#define mk make_pair
using namespace std;
const int maxn=3e5+10;
ll mn[maxn];
int sz[maxn],son[maxn],top[maxn],id[maxn],dep[maxn];
int a[maxn],s[maxn],f[maxn],cnt,Top;
vector<P>G[maxn];
vector<int>G2[maxn];
bool cmp(int x,int y) {
return id[x]<id[y];
}
void dfs1(int u,int fa,int deep)
{
f[u]=fa;
dep[u]=deep;
sz[u]=1;
for(auto tmp : G[u]) {
int v = tmp.first;
if (v == fa)
continue;
mn[v]=min(mn[u], 1ll*tmp.second);
dfs1(v,u,deep+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])
son[u]=v;
}
}
void dfs2(int u,int rt)
{
top[u]=rt;
id[u]=++cnt;
if(son[u])
dfs2(son[u],rt);
for(auto tmp : G[u]) {
int v = tmp.first;
if (v != f[u] && v != son[u])
dfs2(v,v);
}
}
int LCA(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]] < dep[top[y]])
swap(x,y);
x=f[top[x]];
}
if(dep[x] > dep[y])
swap(x,y);
return x;
}
void add(int x,int y)
{
G2[x].push_back(y);
}
void insert(int x) {
if (Top == 1) {
s[++Top] = x;
return;
}
int lca = LCA(s[Top], x);
if (lca == s[Top])
return;
while (Top > 1 && id[s[Top-1]] >= id[lca])
add(s[Top-1], s[Top]),Top--;
if (lca != s[Top])
add(lca, s[Top]), s[Top]=lca;
s[++Top] = x;
}
ll dfs(int u)
{
if (G2[u].size() == 0)
return mn[u];
ll res = 0;
for (auto v : G2[u])
res += dfs(v);
G2[u].clear();
return min(res, mn[u]);
}
int main()
{
int n,m,k,u,v,w;
scanf("%d",&n);
for (int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
G[u].push_back(mk(v,w));
G[v].push_back(mk(u,w));
}
mn[1]=1e18;
dfs1(1,0,1);
dfs2(1,1);
scanf("%d",&m);
while(m--) {
scanf("%d",&k);
for (int i = 1; i <= k; ++i)
scanf("%d",&a[i]);
sort(a+1, a+1+k, cmp);
s[Top = 1] = 1;
for (int i = 1; i <= k; ++i)
insert(a[i]);
while (Top > 1)
add(s[Top - 1], s[Top]),Top--;
printf("%lld\n",dfs(1));
}
}