大概入门了一下虚树, 感觉虚树其实就是对暴力dfs的优化, 只保留了些有效信息的点, 最后用栈模拟dfs.
板子题 洛谷 P2495
#include <iostream> #include <algorithm> #include <cstdio> #include <vector> #define pb push_back #define PER(i,a,n) for(int i=n;i>=a;--i) #define REP(i,a,n) for(int i=a;i<=n;++i) using namespace std; typedef long long ll; const int N = 4e5+10, INF = 0x7f7f7f7f; int n, m; int L[N], R[N], dep[N]; int vis[N], tr[N<<2], mi[N]; int fa[N][25]; ll sum[N]; vector<int> s; struct _ {int to,w;}; vector<_> g[N]; void dfs(int x, int f) { L[x] = ++*L, fa[x][0] = f; for (int i=1; fa[x][i-1]; ++i) { fa[x][i] = fa[fa[x][i-1]][i-1]; } for (auto e:g[x]) if (e.to!=f) { int y = e.to; mi[y] = min(mi[x], e.w); dep[y] = dep[x]+1; dfs(y, x); } R[x] = ++*L; } int lca(int x, int y) { if(dep[x]<dep[y]) swap(x,y); PER(i,0,20) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if (x==y) return x; PER(i,0,20) if (fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i]; return fa[x][0]; } bool cmp(int x, int y) { int k1=(x>0?L[x]:R[-x]); int k2=(y>0?L[y]:R[-y]); return k1<k2; } int main() { scanf("%d", &n); REP(i,2,n) { int u, v, w; scanf("%d%d%d", &u, &v, &w); g[u].pb({v,w}); g[v].pb({u,w}); } mi[1] = INF, dep[1]=1, dfs(1,0); scanf("%d", &m); while (m--) { scanf("%d", tr); REP(i,1,*tr) { scanf("%d", tr+i); vis[tr[i]] = 1; sum[tr[i]] = mi[tr[i]]; } sort(tr+1,tr+1+*tr,cmp); REP(i,1,*tr-1) { int x = lca(tr[i],tr[i+1]); if (!vis[x]) { tr[++*tr] = x; vis[x] = 1; } } if (!vis[1]) tr[++*tr]=1; int t = *tr; REP(i,1,t) tr[++*tr]=-tr[i]; sort(tr+1,tr+1+*tr,cmp); REP(i,1,*tr) { if (tr[i]>0) { s.push_back(tr[i]); continue; } int x = s.back();s.pop_back(); if (x==1) printf("%lld\n", sum[1]); else { int f = s.back(); sum[f] += min(sum[x], (ll)mi[x]); } sum[x] = 0, vis[x] = 0; } } }