虚树+树形DP
建虚树的时候,清空数组可能被卡
由于需要查询原树上两点之间权值最小的边,所以用到了树剖。
LCA一开始用的欧拉序列,后来发现树剖也可以接受。
// luogu-judger-enable-o2
#include
#include
#include
#include
#include
#include
#include
#include
using std::cin;
using std::cout;
using std::endl;
using std::vector;
using int_t = int_fast64_t;
const int_t LARGE = 300000;
int_t read()
{
int_t x;
scanf("%lld", &x);
return x;
}
void print(int_t x)
{
printf("%lld", x);
}
struct Struct
{
int_t depth;
int_t vertex;
};
bool operator<(const Struct a, const Struct b)
{
return a.depth < b.depth;
}
struct Edge
{
int_t to;
int_t weight;
};
vector graph[LARGE + 1];
int_t counter = 0;
Struct ST[LARGE * 2 + 2 + 1][20];
int_t dfsSeq[LARGE + 1];
int_t depth[LARGE + 1];
int_t values[LARGE + 1];
int_t maxChild[LARGE + 1];
int_t size[LARGE + 1];
int_t T_ST[LARGE + 1];
int_t ST_T[LARGE + 1];
int_t top[LARGE + 1];
int_t ST2[LARGE + 1][20];
int_t parent[LARGE + 1];
int_t pow2[LARGE + 1];
int_t DFSN[LARGE + 1];
int_t first[LARGE + 1];
int_t n, m;
void pushedge(int_t from, int_t to, int_t weight)
{
graph[from].push_back({to, weight});
graph[to].push_back({from, weight});
}
int_t DFS0(int_t vertex, int_t from = -1, int_t depth = 1)
{
ST[++counter][0] = {depth, vertex};
dfsSeq[++dfsSeq[0]] = vertex;
if (from == -1)
values[vertex] = (int64_t)0x7fffffff;
size[vertex] = 1;
int_t maxChildID = -1;
int_t maxChildN = 0;
for (auto &edge : graph[vertex])
{
if (edge.to != from)
{
values[edge.to] = edge.weight;
int_t x = DFS0(edge.to, vertex, depth + 1);
ST[++counter][0] = {depth, vertex};
if (x > maxChildN)
{
maxChildN = x;
maxChildID = edge.to;
}
size[vertex] += x;
}
}
maxChild[vertex] = maxChildID;
return size[vertex];
}
void DFS(int_t vertex, int_t from = -1, int_t depth = 1)
{
parent[vertex] = from;
if (from == -1)
top[vertex] = vertex;
ST_T[0]++;
ST_T[ST_T[0]] = vertex;
T_ST[vertex] = ST_T[0];
if (maxChild[vertex] > 0)
{
top[maxChild[vertex]] = top[vertex];
DFS(maxChild[vertex], vertex, depth + 1);
}
::depth[vertex] = depth;
for (auto &edge : graph[vertex])
{
if (edge.to != from && edge.to != maxChild[vertex])
{
top[edge.to] = edge.to;
DFS(edge.to, vertex, depth + 1);
}
}
}
void init()
{
DFS0(1);
DFS(1);
for (int_t i = 1; i <= n; i++)
ST2[i][0] = values[ST_T[i]];
for (int_t j = 1; pow2[j] <= n; j++)
{
for (int_t i = 1; i + pow2[j] - 1 <= n; i++)
{
ST2[i][j] = std::min(ST2[i][j - 1], ST2[i + pow2[j - 1]][j - 1]);
}
}
for (int_t j = 1; pow2[j] <= counter; j++)
{
for (int_t i = 1; i + pow2[j] - 1 <= counter; i++)
{
ST[i][j] = std::min(ST[i][j - 1], ST[i + pow2[j - 1]][j - 1]);
}
}
for (int_t i = 1; i <= counter; i++)
{
if (first[ST[i][0].vertex] == 0)
{
first[ST[i][0].vertex] = i;
}
}
for (int_t i = 1; i <= n; i++)
{
DFSN[dfsSeq[i]] = i;
}
}
int_t getLCA(int_t v1,int_t v2) {
int_t top1=top[v1];
int_t top2=top[v2];
while(top1!=top2){
if(depth[top1] b)
// std::swap(a, b);
// int_t k = log2(b - a + 1);
// return std::min(ST[a][k], ST[b - pow2[k] + 1][k]).vertex;
//}
int_t queryST2(int_t a, int_t b)
{
if (a > b)
return 0x7fffffff;
int_t k = log2(b - a + 1);
// printf("ST2 %d(rt:%d) %d(rt:%d) k = %d = %d\n",a,ST_T[a],b,ST_T[b],k,std::min(ST2[a][k],ST2[b-pow2[k]+1][k]));
// cout< depth[v2])
std::swap(v1, v2);
result = std::min(result, queryST2(T_ST[v1] + 1, T_ST[v2]));
return result;
}
auto func = [&](int_t a, int_t b) -> bool {
return DFSN[a] < DFSN[b];
};
struct Processor
{
std::unordered_map> graph;
bool rich[LARGE + 1];
int_t n;
int_t querys[LARGE * 2 + 1];
int_t cnt = 0;
void pushedge(int_t from, int_t to)
{
// if(graph.count(from)==false) graph[from]=vector();
// if(graph.count(to)==false) graph[to]=vector();
graph[from].push_back(to);
graph[to].push_back(from);
}
void process()
{
cnt = 0;
graph.clear();
n = read();
querys[++cnt] = 1;
for (int_t i = 1; i <= n; i++)
{
int_t x;
x = read();
querys[++cnt] = x;
rich[x] = true;
}
std::sort(&querys[1], &querys[cnt + 1], func);
int_t size = cnt;
for (int_t i = 1; i < size; i++)
{
querys[++cnt] = getLCA(querys[i], querys[i + 1]);
}
std::sort(&querys[1], &querys[cnt + 1], func);
cnt = (std::unique(&querys[1], &querys[cnt + 1]) - &querys[1]);
std::stack stack;
for (int_t i = 1; i <= cnt; i++)
{
int_t vertex = querys[i];
if (stack.empty())
{
stack.push(vertex);
continue;
}
while (getLCA(stack.top(), vertex) != stack.top())
stack.pop();
pushedge(stack.top(), vertex);
stack.push(vertex);
}
print(search(1));
putchar('\n');
for (int_t i=1;i<=cnt;i++)
rich[querys[i]] = false;
}
int_t search(int_t vertex, int_t from = -1)
{
int_t result = 0;
for (auto x : graph[vertex])
{
if (x != from)
{
if (rich[x])
{
result += minEdge(x, vertex);
}
else
{
result += std::min(minEdge(x, vertex), search(x, vertex));
}
}
}
return result;
}
} p;
int main()
{
// freopen("data.txt","r",stdin);
// freopen("out1.txt","w",stdout);
for (int_t i = 1; i <= 21; i++)
{
pow2[0] = 1;
pow2[i] = pow2[i - 1] * 2;
}
n = read();
for (int_t i = 1; i <= n - 1; i++)
{
int_t from, to, weight;
from = read();
to = read();
weight = read();
pushedge(from, to, weight);
}
init();
int_t m = read();
for (int_t i = 1; i <= m; i++)
{
p.process();
}
return 0;
}