2025.04.12 CW 模拟赛 C. 通信网络
C. 通信网络
题目描述
SH 的家乡 Y 市采购了一批先进的通信网络教学用具,用来给中学生演示通信原理。
这种工具有 \(N\) 个通信基站和 \(N-1\) 条数据链路构成,每个通信基站有一个基本的信号频率 \(w_i\),每条数据链路连接两个通信基站,保证任何两个基站可以通过数据链路相互到达。
这个通信网络是一个整体的信号强度 \(P\) 的。两个通信基站 \(u, v\) 之间能够相互通信,当且仅当:
两个基站的最短路上,经过了至少一个基站 \(z\),使得基站 \(z\) 满足 \(w_u - w_z \leq P\) 且 \(w_v - w_z \leq P\),此处 \(z\) 可以等于 \(u\) 或者 \(v\),这样的 \(z\) 被称作 \(u\) 和 \(v\) 的中继基站。注意,一对节点 \((u, v)\) 的中继基站可能有多个。
一个基站的负荷指的是,这个基站承载了多少对基站的通信,也就是说,这个基站是多少个有序对 \((u, v)\) 的中继基站。
现在,请帮助 Y 市确定一个最大的信号强度 \(P\),使得每个基站的负荷都小于给定的值 \(K\)。
思路
首先有一个 \(\mathcal{O}(n^2 \log n)\) 的思路: 我们二分 \(P\), 在 \(\text{check}\) 的时候我们枚举每一个作为中继点的贡献. 算贡献时以当前枚举点为根, 递归到子树里面暴力统计即可.
发现我们递归到子树内暴力统计太慢了, 本质上我们统计的其实是 \(w_v \le P + w_u\) 的 \(v\) 的数量. 又因为在树上一个子树的 \(\text{DFS}\) 序一定是连续的, 所以考虑建主席树, 对于第 \(i\) 个版本我们就插入 \(\text{DFS}\) 序为 \(i\) 的点的权值, 查询的区间就是
时间复杂度 \(\mathcal{O}(n \log^2 n)\).
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
char buf[1 << 20], *p1, *p2;
#define getchar() (p1 == p2 and (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? 0 : *p1++)
template <class T>
void read(T& x) {
x = 0; char c = getchar();
while (c < '0' or c > '9') {
c = getchar();
}
while (c >= '0' and c <= '9') {
x = x * 10 + (c & 15);
c = getchar();
}
}
constexpr int N = 300001, M = 10000001;
int n, a[N], rt[N], tmp[N], len;
ll k;
int w[N], dfn[N], sz[N], fa[N], id;
vector<int> e[N];
class SegmentTree {
private:
int tot;
int tr[M], ls[M], rs[M];
public:
int build(int l, int r) {
int u = ++tot;
if (l == r) {
return u;
}
int mid = (l + r) >> 1;
ls[u] = build(l, mid);
rs[u] = build(mid + 1, r);
return u;
}
int update(int pre, int l, int r, int x) {
int u = ++tot;
tr[u] = tr[pre] + 1;
ls[u] = ls[pre], rs[u] = rs[pre];
if (l == r) {
return u;
}
int mid = (l + r) >> 1;
x <= mid ? ls[u] = update(ls[pre], l, mid, x) : rs[u] = update(rs[pre], mid + 1, r, x);
return u;
}
int query(int x, int y, int l, int r, int k) {
if (l == r) {
return tr[y] - tr[x];
}
int mid = (l + r) >> 1, res;
if (k <= mid) {
res = query(ls[x], ls[y], l, mid, k);
}
else {
res = tr[ls[y]] - tr[ls[x]];
res += query(rs[x], rs[y], mid + 1, r, k);
}
return res;
}
int query(int l, int r, int k) {
l = rt[l - 1], r = rt[r];
return query(l, r, 1, len, k);
}
} seg;
bool check(int P) {
for (int i = 1; i <= n; ++i) {
vector<int> v;
ll sum = 0, tot = 0;
int lim = upper_bound(tmp + 1, tmp + len + 1, a[i] + P) - tmp - 1;
for (int j : e[i]) {
int val;
if (j == fa[i]) {
val = seg.query(1, dfn[i] - 1, lim) + seg.query(dfn[i] + sz[i], n, lim);
if (val > 0) {
v.push_back(val);
}
}
else {
val = seg.query(dfn[j], dfn[j] + sz[j] - 1, lim);
if (val > 0) {
v.push_back(val);
}
}
sum += val;
}
P >= 0 and (tot += sum);
for (int x : v) {
sum -= x;
tot += x * sum;
}
if (tot >= k) {
return false;
}
}
return true;
}
void init() {
read(n), read(k);
for (int i = 1; i <= n; ++i) {
read(a[i]);
tmp[++len] = a[i];
}
for (int i = 1; i < n; ++i) {
int u, v;
read(u), read(v);
e[u].push_back(v);
e[v].push_back(u);
}
auto dfs = [](auto&& self, int u, int f) -> void {
sz[u] = 1, fa[u] = f;
w[dfn[u] = ++id] = a[u];
for (int v : e[u]) {
if (v == f) {
continue;
}
self(self, v, u);
sz[u] += sz[v];
}
};
dfs(dfs, 1, 0);
sort(tmp + 1, tmp + len + 1);
len = unique(tmp + 1, tmp + len + 1) - tmp - 1;
rt[0] = seg.build(1, len);
for (int i = 1; i <= n; ++i) {
int t = lower_bound(tmp + 1, tmp + len + 1, w[i]) - tmp;
rt[i] = seg.update(rt[i - 1], 1, len, t);
}
}
void calculate() {
int l = -1e6, r = 1e6, mid, ans = l;
while (l <= r) {
mid = (l + r) / 2;
if (check(mid)) {
l = mid + 1;
ans = mid;
}
else {
r = mid - 1;
}
}
printf("%d\n", ans);
}
void solve() {
init();
calculate();
}
int main() {
solve();
return 0;
}

浙公网安备 33010602011771号