【模板】虚树
似乎虚树的思想就是就是要把没用的点和边去掉,然后建一棵仅包含关键点的虚树。
过程中我们维护了一条“右链”。
其实除了规定的关键点,两两关键点的\(LCA\)也是必要的点。
struct VEDGE {
int t, next;
} vedge[E];
int vedge_tot, vhead[V];
void add_vedge(int f,int t) {
vedge[++vedge_tot].next = vhead[f];
vedge[vedge_tot].t = t;
vhead[f] = vedge_tot;
}
bool comp(const int &_x,const int &_y) {
return dfn[_x] < dfn[_y];
}
int stk[V], h[V], k;
void VT_con() {
std :: sort(h+1,h+k+1,comp);
stk[++stk[0]] = 1;
vhead[1] = 0;
for(int i = 1;i <= k;++i) {
if(h[i] == 1)
continue;
int l = LCA(h[i],stk[stk[0]]);
if(l != stk[stk[0]]) {
while(dfn[l] < dfn[stk[stk[0]-1]]) {
add_vedge(stk[stk[0]],stk[stk[0]-1]);
add_vedge(stk[stk[0]-1],stk[stk[0]]);
stk[0]--;
}
if(dfn[l] > dfn[stk[stk[0]-1]]) {
vhead[l] = 0;
add_vedge(l,stk[stk[0]]);
add_vedge(stk[stk[0]],l);
stk[stk[0]] = l;
} else {
add_vedge(l,stk[stk[0]]);
add_vedge(stk[stk[0]],l);
stk[0]--;
}
}
vhead[h[i]] = 0;
stk[++stk[0]] = h[i];
}
for(int i = 1;i < stk[0];++i) {
add_vedge(stk[i],stk[i+1]);
add_vedge(stk[i+1],stk[i]);
}
}
设\(\delta_i\)为\(i\)到\(1\)节点路上的最小权值,则有方程\(dp_u=\begin{cases}\min(\delta_u,\sum\limits_{u->v}dp_v)&u\text{不是关键节点}\\\delta_u&u\text{是关键节点}\end{cases}\)
code
#include <stdio.h>
#include <queue>
#include <math.h>
#include <bits/stl_algo.h>
const int V = 250010;
const int E = 500010;
struct EDGE {
int t, next, w;
} edge[E];
int edge_tot, head[V];
void add_edge(int f,int t,int w) {
edge[++edge_tot].next = head[f];
edge[edge_tot].t = t;
edge[edge_tot].w = w;
head[f] = edge_tot;
}
int depth[V], parent[V][18], logup, dfn[V], time;
long long mn[V];
std :: queue<int> q;
void dfs(int u,int p) {
dfn[u] = ++time;
parent[u][0] = p;
depth[u] = depth[p]+1;
logup = log(depth[u])/log(2)+1;
for(int i = 1;i <= logup;++i)
parent[u][i] = parent[parent[u][i-1]][i-1];
for(int i = head[u];i;i = edge[i].next) {
int v = edge[i].t;
if(v == p)
continue;
mn[v] = std :: min(mn[u],1ll*edge[i].w);
dfs(v,u);
}
}
int LCA(int u,int v) {
if(depth[u] > depth[v])
std :: swap(u,v);
logup = log(depth[v])/log(2)+1;
for(int i = logup;i >= 0;--i)
if(depth[parent[v][i]] >= depth[u])
v = parent[v][i];
if(u == v) return u;
logup = log(depth[v])/log(2)+1;
for(int i = logup;i >= 0;--i)
if(parent[u][i] != parent[v][i]) {
u = parent[u][i];
v = parent[v][i];
}
return parent[u][0];
}
struct VEDGE {
int t, next;
} vedge[E];
int vedge_tot, vhead[V];
void add_vedge(int f,int t) {
vedge[++vedge_tot].next = vhead[f];
vedge[vedge_tot].t = t;
vhead[f] = vedge_tot;
}
bool comp(const int &_x,const int &_y) {
return dfn[_x] < dfn[_y];
}
int stk[V], h[V], k;
bool ck[V];
void VT_con() {
std :: sort(h+1,h+k+1,comp);
vedge_tot = 0;
stk[stk[0] = 1] = 1;
vhead[1] = 0;
for(int i = 1;i <= k;++i) {
if(h[i] == 1)
continue;
int l = LCA(h[i],stk[stk[0]]);
if(l != stk[stk[0]]) {
while(dfn[l] < dfn[stk[stk[0]-1]]) {
add_vedge(stk[stk[0]],stk[stk[0]-1]);
add_vedge(stk[stk[0]-1],stk[stk[0]]);
stk[0]--;
}
if(dfn[l] > dfn[stk[stk[0]-1]]) {
vhead[l] = 0;
add_vedge(l,stk[stk[0]]);
add_vedge(stk[stk[0]],l);
stk[stk[0]] = l;
} else {
add_vedge(l,stk[stk[0]]);
add_vedge(stk[stk[0]],l);
stk[0]--;
}
}
vhead[h[i]] = 0;
stk[++stk[0]] = h[i];
}
for(int i = 1;i < stk[0];++i) {
add_vedge(stk[i],stk[i+1]);
add_vedge(stk[i+1],stk[i]);
}
}
long long vdfs(int u,int p) {
long long temp = 0;
for(int i = vhead[u];i;i = vedge[i].next) {
int v = vedge[i].t;
if(v == p)
continue;
temp += vdfs(v,u);
}
temp = (ck[u] ? mn[u] : std :: min(1ll*mn[u],temp));
ck[u] = false;
return temp;
}
int n, m;
signed main() {
scanf("%d",&n);
for(int i = 1, a, b, c;i < n;++i) {
scanf("%d %d %d\n",&a,&b,&c);
add_edge(a,b,c);
add_edge(b,a,c);
}
mn[1] = 99998244353;
dfs(1,0);
scanf("%d",&m);
for(int i = 1;i <= m;++i) {
scanf("%d",&k);
for(int j = 1;j <= k;++j) {
scanf("%d",&h[j]);
ck[h[j]] = true;
}
VT_con();
printf("%lld\n",vdfs(1,0));
}
}