Step1 Problem:
给你 n 个点,m 条无向边,边有边权。
有 Q 个询问:
询问给出一条边:u, v,让你输出包含 u, v 这条边的最小生成树的花费。
数据范围:
2 <= n <= 1e5, n-1 <= m <= 2e5, 1 <= Q <= 1e5.
Step2 Ideas:
对于给定的图,找出最小生成树,和最小生成树边权和 sum。
询问边 u, v 在树上:输出 sum.
询问边 u, v 不在树上:找出树上路径 u->v 最大边权,输出 sum + 询问边 - 最大边权。
核心就是解决路径 u->v 最大边权问题:
1:我们可以树剖,维护链的最大值。
2:求出 u, v 的 lca,u->lca 边权最大值 和 v->lca 边权最大值 取最大。
对于 2:我们就整个 ST 表,dp[u][i]:代表 u->fq[u][i] 边权最大值,其中 fq[u][i]: 代表 u 的第 (1<
Step3 Code:
#include
using namespace std;
const int N = 2e5+5;
struct node
{
int u, v, val;
bool operator < (const node &b) const {
return val < b.val;
}
};
node a[N];
vector Map[N];
int fq[N][20], dep[N];
int dp[N][20], mn[N];
void dfs(int u, int f, int step, int v)
{
fq[u][0] = f, dep[u] = step;
dp[u][0] = v;// u->f 的边权
for(int i = 1; i < 20; i++)//预处理 fq, dp.
{
fq[u][i] = fq[fq[u][i-1]][i-1];
dp[u][i] = max(dp[u][i-1], dp[fq[u][i-1]][i-1]);
}
for(int i = 0; i < Map[u].size(); i++)
{
int to = Map[u][i].v, val = Map[u][i].val;
if(to != f) {
dfs(to, u, step+1, val);
}
}
}
int Lca(int x, int y)
{
if(dep[x] > dep[y]) swap(x, y);
for(int i = 0; i < 20; i++)
{
if((dep[y]-dep[x])>>i&1) {
y = fq[y][i];
}
}
if(x == y) return x;
for(int i = 19; i >= 0; i--)
{
if(fq[x][i] != fq[y][i]) {
x = fq[x][i];
y = fq[y][i];
}
}
return fq[x][0];
}
void get_mn()
{
for(int len = 1; len < 100005; len++)
{
int k = 0;
while((1<<(k+1)) <= len) k++;
mn[len] = k;
}
}
int path_Max(int x, int y)//y 是 x 的祖先
{
int t = dep[x]-dep[y];
if(t == 0) return 0;
else {
int f = x;//找到 y 往 x 方向第 (1<= 0; i--)
{
if(dep[fq[f][i]] - dep[y] >= (1<y 边权最大值
}
}
int f[N];
int Find(int x)
{
if(x == f[x]) return x;
else return f[x] = Find(f[x]);
}
void Merge(int x, int y)
{
x = Find(x), y = Find(y);
if(x != y) f[y] = x;
}
map< pair, int > has;
int main()
{
get_mn();
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) f[i] = i;
for(int i = 1; i <= m; i++)
{
scanf("%d %d %d", &a[i].u, &a[i].v, &a[i].val);
has[make_pair(a[i].u, a[i].v)] = a[i].val;
has[make_pair(a[i].v, a[i].u)] = a[i].val;
}
sort(a+1, a+1+m);
int sum = 0, x, y;
for(int i = 1; i <= m; i++)
{
x = Find(a[i].u), y = Find(a[i].v);
if(x != y) {
Merge(x, y);
sum += a[i].val;
Map[a[i].u].push_back((node){a[i].u, a[i].v, a[i].val});
Map[a[i].v].push_back((node){a[i].v, a[i].u, a[i].val});
}
}
memset(dp, 0, sizeof(dp));
dfs(1, 1, 1, 0);
int Q;
scanf("%d", &Q);
while(Q--)
{
scanf("%d %d", &x, &y);
int val = has[make_pair(x, y)];
int lca = Lca(x, y);
printf("%d\n", sum+val-max(path_Max(x, lca), path_Max(y, lca)));
}
return 0;
}