一道虚树模板题,虚树的写法我是写一个栈然后跑LCA的。
虚树建完之后一个树形DP就跑过去了。
#include<bits/stdc++.h>
using namespace std;
const int N = 250005 * 2;
const int K = N;
const int M = N * 3;
#define int long long
int st[N][32] , val[N][32] , cnt , stk[N] , top , node[N] , tot , lca ,depth[N] , dfn[N] , nodesize;
int fir[N] , ne[M] , to[M] , C[M] , dp[N] , dfs_clock , out[N] , root;
vector<int>G[N] , Val[N];
void add(int x ,int y ,int z) {
ne[++ cnt] = fir[x]; fir[x] = cnt; to[cnt] = y; C[cnt] = z;
}
void link(int x ,int y,int z) {
add(x,y,z);
add(y,x,z);
}
#define Foreachson(i,x) for(int i = fir[x];i;i = ne[i])
void dfs(int x, int f , int fe) {
depth[x] = depth[f] + 1;
st[x][0] = f;
val[x][0] = C[fe];
dfn[x] = ++ dfs_clock;
for(int i = 1;i <= 30;i ++) {
st[x][i] = st[st[x][i-1]][i-1];
val[x][i] = min(val[x][i - 1] , val[st[x][i-1]][i-1]);
}
Foreachson(i,x) {
int V = to[i];
if(V != f) {
dfs(V,x,i);
}
}
out[x] = ++ dfs_clock;
}
int LCA_no(int x ,int y) {
if(x == y) return x;
if(depth[x] > depth[y]) swap(x,y);
for(int i = 30;i >= 0;i --) {
if(depth[st[y][i]] >= depth[x]) y= st[y][i];
}
if(x == y) return x;
for(int i = 30;i >= 0;i --) {
if(st[y][i] != st[x][i]) {
y = st[y][i];
x = st[x][i];
}
}
return st[x][0];
}
int LCA_val(int x ,int y) {
if(x == y) while(1) cerr <<"Wrong Answer!"<<endl;
int res = 2e9;
if(depth[x] > depth[y]) swap(x,y);
for(int i = 30;i >= 0;i --) {
if(depth[st[y][i]] >= depth[x]) {
res = min(res,val[y][i]);
y = st[y][i];
}
}
if(x == y) return res;
for(int i = 30;i >= 0;i --) {
if(st[y][i] != st[x][i]) {
res = min(res,val[y][i]);
y = st[y][i];
res = min(res,val[x][i]);
x = st[x][i];
}
}
return min(res , min(val[x][0],val[y][0]));
}
bool check(int x ,int y) {
return (dfn[x] <= dfn[y] && out[x] >= out[y]);
}
bool cmp(int x ,int y) {
return dfn[x] < dfn[y];
}
int vis[N];
void newnode(int x ,int t) {
if(vis[x] == t) return;
vis[x] = t;
G[x].clear();
Val[x].clear();
}
void newadd(int x ,int y,int z) {
G[x].push_back(y);
Val[x].push_back(z);
G[y].push_back(x);
Val[y].push_back(z);
}
int List[N * 2];
int in[N];
void dop(int x ,int f , int t) {
dp[x] = 0;
for(int i = 0;i <(int) G[x].size();i ++) {
int V = G[x][i] , F = Val[x][i];
if(V == f) continue;
dop(V,x,t);
if(in[V] == t) dp[x] += F;
else dp[x] += min(dp[V] , F);
}
}
void build(int t) {
int len;
len = 0;
scanf("%lld",&tot);
List[++ len] = 1;
for(int i = 2;i <= tot + 1;i ++) scanf("%lld",&List[i]) , in[List[i]] = t;
len = tot + 1;
//果然是要sort两遍。。。
sort(List + 1, List + len + 1, cmp);
for(int i = 1;i <= tot;i ++) {
List[++ len] = LCA_no(List[i] , List[i + 1]);
}
sort(List + 1, List + len + 1, cmp);
len = unique(List + 1,List + len +1) - List - 1;
for(int i = 1;i <= len ;i ++) {
G[List[i]].clear();
Val[List[i]].clear();
}
top = 0;
for(int i = 1;i <= len;i ++) {
while(top > 0 && !check(stk[top],List[i])) top --;
if(!top) root = List[i];
else {
newadd(stk[top] , List[i] , LCA_val(stk[top],List[i]));
}
stk[++ top] = List[i];
}
for(int i = 1;i <= len;i ++) {
dp[List[i]] = 1e18 + 666;
}
dop(1,0,t);
printf("%lld\n",dp[1]);
}
int n , m;
signed main() {
scanf("%lld",&n);
for(int i = 1 , x, y, z;i <= n- 1;i ++) {
scanf("%lld%lld%lld",&x,&y,&z);
link(x,y,z);
}
dfs(1,0,0);
scanf("%lld",&m);
for(int i = 1;i <= m;i ++) build(i);
}