虚树
感觉还挺简单的(?
虚树的作用就是提取关键点和路径价值,以优化复杂度
然后有一种二次排序做法似乎是近几年才出现的,感觉这个做法好方便好妙呀
先将关键点按 dfn 序排,然后将两两之间的 LCA 放入序列,去个重
然后再排一次序,将相邻的两个点的 LCA 与后一个点相连
P2495 【模板】虚树 / [SDOI2011] 消耗战
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" = "<<x<<endl;
const int N = 2.5e5 + 5;
int n, m, k, p[N], a[N*2], dep[N], num, dfn[N], go[N][20], f[N][20];
ll dp[N];
bool mark[N];
struct Edge{
ll to, w;
};
vector<Edge> g[N], G[N];
inline ll read(){
ll s=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<1)+(s<<3)+(c^48);c=getchar();}
return s*f;
}
bool cmp(int x, int y){
return dfn[x] < dfn[y];
}
void dfs_pretreat(int x, int fa){
dep[x] = dep[fa] + 1;
go[x][0] = fa;
dfn[x] = ++num;
for(int i=0;i<g[x].size();i++){
int t = g[x][i].to;
if(t == fa)continue;
f[t][0] = g[x][i].w;
dfs_pretreat(t, x);
}
}
int lca(int x, int y){
if(dep[x] < dep[y])swap(x, y);
for(int i=19;i>=0;i--)if(dep[go[x][i]] >= dep[y])x = go[x][i];
if(x == y)return x;
for(int i=19;i>=0;i--)if(go[x][i] != go[y][i])x = go[x][i], y = go[y][i];
return go[x][0];
}
int dis(int x, int y){
if(dep[x] < dep[y])swap(x, y);
int ans = 0x3f3f3f3f;
for(int i=19;i>=0;i--)if(dep[go[x][i]] >= dep[y])ans = min(ans, f[x][i]), x = go[x][i];
return ans;
}
void dfs(int x, int fa){
for(int i=0;i<G[x].size();i++){
int t = G[x][i].to;
if(t == fa)continue;
dfs(t, x);
if(mark[t])dp[x] += G[x][i].w;
else dp[x] += min(dp[t], G[x][i].w);
}
}
int main(){
n = read();
for(int i=1;i<n;i++){
int u = read(), v = read(), w = read();
g[u].push_back(Edge{v, w});
g[v].push_back(Edge{u, w});
}
memset(f, 0x3f, sizeof f);
dfs_pretreat(1, 0);
for(int t=1;t<=19;t++)
for(int i=1;i<=n;i++)
go[i][t] = go[go[i][t-1]][t-1], f[i][t] = min(f[i][t-1], f[go[i][t-1]][t-1]);
m = read();
while(m--){
k = read();
for(int i=1;i<=k;i++)mark[p[i] = read()] = true;
int len = 0;
sort(p+1, p+k+1, cmp);
for(int i=1;i<k;i++){
a[++len] = p[i];
a[++len] = lca(p[i], p[i+1]);
}
a[++len] = 1;
a[++len] = p[k];
sort(a+1, a+len+1, cmp);
len = unique(a+1, a+len+1) - a - 1;
for(int i=1;i<len;i++){
int LCA = lca(a[i], a[i+1]);
int w = dis(a[i+1], LCA);
G[LCA].push_back(Edge{a[i+1], w});
}
dfs(1, 0);
cout << dp[1] << endl;
for(int i=1;i<=len;i++){
int LCA = lca(a[i], a[i+1]);
G[LCA].clear();
dp[a[i]] = mark[a[i]] = 0;
}
}
return 0;
}

浙公网安备 33010602011771号