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\) 的点的权值, 查询的区间就是

\[\begin{cases} [1, \text{dfn}_u) \cup [\text{dfn}_u + \text{size}_u, n] & v = fa_u \\ [\text{dfn}_v, \text{dfn}_v + \text{size}_v) & v \in son_u \end{cases} \]

时间复杂度 \(\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;
}
posted @ 2025-04-14 11:51  Steven1013  阅读(22)  评论(0)    收藏  举报