题解:CF1633E Spanning Tree Queries
我们可以大概意识到, 如果将询问的 \(x\) 按顺序进行查询的话会出现一些性质.
但这不是非常明确, 而且观察到不能对 \(10^8\) 个值全部计算 MST.
我们接下来要考虑想办法选取一些关键的 \(x\) 值进行计算, 我们想要找到关键的少数 \(x\), 然后对这些值计算.
我们研究 Kruskal 算法中边被处理的先后顺序.
考虑一对边, 边权 \(w_1\), \(w_2\), 令 \(w_1 \lt w_2\).
在 \(x\) 从 \(0\) 开始不断增大的过程中, 总是存在一个 \(x\) 会使得 \(w_2\) 离 \(x\) 更近, \(w_2\) 在此及之后会先被考虑.
在 \(w_1 \leqslant x \leqslant w_2\) 中会出现这个分界线.
解一下.
\(x \leqslant \frac{w_1 + w_2}{2}\) 时, 选 \(w_1\) 优.
\(x \geqslant \lfloor \frac{w_1 + w_2}{2} \rfloor + 1\) 时, 选 \(w_2\) 优.
最开始是选 \(w_1\) 优的, 所以将 \(\lfloor \frac{w_1 + w_2}{2} \rfloor + 1\) 设为分界线.
踩到分界线的时候会交换 \(w_1\) 和 \(w_2\) 的顺序, 这时对 MST 有影响, 需要重新计算.
不踩到分界线的时候, 不用交换.
同时考虑, 因为绝对值的原因, 所有给定的边权也需要设成分界线.
所以只有 \(O(m^2)\) 条分界线, 对每个分界线处用 Kruskal 做一次 MST.
查询的时候看给定的询问的 \(x\) 最后踩到的分界线是谁, 用这个分界线处的答案计算即可.
在这个题中, 我们需要注意:
-
如果需要多个值进行多次计算的时候, 观察一下是不是有很多值处的处理方式或答案构成是一样的, 只需要选取几个对答案有关键影响的关键点分界线处计算即可.
-
在考虑分界线形成的时候, 需要细化考虑, 将答案的贡献放到每一对边上, 这样可以方便找到分界线的位置.
\(Code\)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <tuple>
using namespace std;
const int NR = 60;
const int MR = 310;
const int TR = 1e5 + 10;
tuple<int, int, long long> e[MR];
long long b[TR];
int sz;
long long res[TR];
int num[TR];
int f[NR];
int find(int x)
{
if (f[x] != x) f[x] = find(f[x]);
return f[x];
}
bool merge(int x, int y)
{
x = find(x), y = find(y);
if (x == y) return false;
f[x] = y;
return true;
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i ++)
{
auto &[x, y, w] = e[i];
scanf("%d%d%lld", &x, &y, &w);
}
b[++sz] = 0;
for (int i = 1; i <= m; i ++)
{
b[++sz] = get<2>(e[i]);
for (int j = 1; j < i; j ++)
{
b[++sz] = (get<2>(e[i]) + get<2>(e[j])) / 2 + 1;
}
}
sort(b + 1, b + sz + 1);
sz = unique(b + 1, b + sz + 1) - b - 1;
for (int cur = 1; cur <= sz; cur ++)
{
sort(e + 1, e + m + 1, [&](const tuple<int, int, long long> &A, const tuple<int, int, long long> &B)
{
return abs(get<2>(A) - b[cur]) < abs(get<2>(B) - b[cur]);
});
for (int i = 1; i <= n; i ++)
{
f[i] = i;
}
int cnt = 0;
for (int i = 1; i <= m; i ++)
{
auto [x, y, w] = e[i];
if (find(x) == find(y)) continue;
merge(x, y);
if (w > b[cur])
{
res[cur] += w;
num[cur] ++;
}
else res[cur] -= w;
cnt ++;
if (cnt == n - 1) break;
}
}
int P, Q;
long long A, B, C;
scanf("%d%d%lld%lld%lld", &P, &Q, &A, &B, &C);
long long lstx = 0;
long long ans = 0;
for (int i = 1; i <= Q; i ++)
{
long long x;
if (i <= P) scanf("%lld", &x);
else x = (lstx * A + B) % C;
lstx = x;
int pos = upper_bound(b + 1, b + sz + 1, x) - b - 1;
long long now = res[pos] - x * num[pos] + x * (n - 1 - num[pos]);
ans ^= now;
}
printf("%lld\n", ans);
return 0;
}

浙公网安备 33010602011771号