G - Sum of Tree Distance

一道很有意思的树上点对 数量计算的问题。。
他实际上是普通的经典 树上点对计算框架的 一个功能扩展。。
也就是加入了同值的概念。。仅此而已。亮点在于深度的存储方式 给计算带来的便利

如果代码看不懂 可以去找一些基本的 树上点对问题统计的题目
实际上树上直径dp。。本质上也是树上点对问题 。
因为直径可以看做是寻找树上最远的两点之间的距离。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll __int128_t
#define ar array<int, 2>
#define arr array<int, 3>
int  n, m, k, inf = 1LL << 61, mod = 998244353;// 1e9+7;
const int N = 5e5 + 50;
map<int, ar>f[N];//节点子树内的 [颜色种类:[数量:深度和]]
vector<int>mp[N];
int  a[N], ans;
void dfs(int u, int p, int d) {
	f[u][a[u]][0]++;
	f[u][a[u]][1] += d;
	for (int v : mp[u]) {
		if (v == p)
			continue;
		dfs(v, u, d + 1);
		if (f[u].size() < f[v].size())
			swap(f[u], f[v]);
		for (auto[t, x] : f[v]) {
			auto &y = f[u][t];
			ans += x[0] * (y[1] - y[0] * d);
			ans += y[0] * (x[1] - x[0] * d);
			// 左点数* 右距离和。。右点数*左距离和。。
			y[0] += x[0];
			y[1] += x[1];
		}
	}
};
void solve() {
	cin >> n;
	for (int i = 1; i < n; ++i) {
		int x, y;
		cin >> x >> y;
		mp[x].push_back(y);
		mp[y].push_back(x);
	}
	for (int i = 1; i <= n; ++i)
		cin >> a[i];

	dfs(1, 0, 0);
	cout << ans;
};


//实际上是很普通的。。启发式合并+树上点对问题的计算方式
// 主要是存储的方式。很有新意 f数组的结构。








signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(15);
#ifdef DEBUG
	freopen("../1.in", "r", stdin);
#endif
	//init_f();
	//init();
	//expr();
	// int T; cin >> T; while(T--)
	solve();
	return 0;
}



增:今天刷题看到一个简单版本的的题目 也就是没有颜色区别 单纯求任意两点的距离和。
https://atcoder.jp/contests/typical90/tasks/typical90_am
039 - Tree Distance

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll __int128_t
#define ar array<int, 2>
#define arr array<int, 3>
int  n, m, k, inf = 1LL << 61, mod = 998244353;// 1e9+7;
const int N = 5e5 + 50;
vector<int>mp[N];
int ans, cnt[N], len[N];
void dfs(int u, int p, int d) {
	cnt[u] = 1;
	len[u] += d;
	for (int v : mp[u]) {
		if (v == p)
			continue;
		dfs(v, u, d + 1);
		ans += cnt[u] * (len[v] - cnt[v] * d);
		ans += cnt[v] * (len[u] - cnt[u] * d);
		cnt[u] += cnt[v];
		len[u] += len[v];
		//也可以用边的贡献来计算 树上距离和 更简单。  不过上面这套。。更适用于上面那道题的扩展。
		//下面还有一道题。。就用下面这种边的贡献来求 更好
		//ans += cnt[v] * (n - cnt[v]);
		//cnt[u] += cnt[v];
	}
};
void solve() {
	cin >> n;
	for (int i = 1; i < n; ++i) {
		int x, y;
		cin >> x >> y;
		mp[x].push_back(y);
		mp[y].push_back(x);
	}
	dfs(1, 0, 0);
	cout << ans;
};




signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(15);
#ifdef DEBUG
	freopen("../1.in", "r", stdin);
#endif
	//init_f();
	//init();
	//expr();
	// int T; cin >> T; while(T--)
	solve();
	return 0;
}



下面这题 又是另外一个方向的 距离和的扩展。。又兴趣的自己去了解 他这个题解写的特别好 虽然短短几句。。但是都说到关键的点子上了。
不过他代码没有我简洁 哈哈哈
https://www.cnblogs.com/wscqwq/p/17591019.html
G - Avoid Straight Line

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll __int128_t
#define ar array<int, 2>
#define arr array<int, 3>
int  n, m, k, inf = 1LL << 61, mod = 998244353;// 1e9+7;
const int N = 5e5 + 50;
vector<int>mp[N];
int ans, cnt[N], len[N];
int C(int n, int m) {
	int ans = 1;
	for (int i = 1; i <= m; i++) {
		ans = ans * (n - m + i) / i; // 注意一定要先乘再除
	}
	return ans;
}
//https://blog.csdn.net/m0_37149062/article/details/122522676
void dfs(int u, int p, int d) {
	cnt[u] = 1;
	for (int v : mp[u]) {
		if (v == p)
			continue;
		dfs(v, u, d + 1);
		ans += cnt[v] * (n - cnt[v]);
		cnt[u] += cnt[v];
	}
};
void solve() {
	cin >> n;
	for (int i = 1; i < n; ++i) {
		int x, y;
		cin >> x >> y;
		mp[x].push_back(y);
		mp[y].push_back(x);
	}
	dfs(1, 0, 0);
	cout << C(n, 3) + C(n, 2) - ans;
};

// 经过u点作为第三个点 的所有两点的组合。。。可以转化成任意两点的距离和问题  len-1 ..
// 为什么要-1
//因为 [1,2,3] 1-3 距离是2 但是实际上中间只能放一个点。。怎么求这个多余的这个点的个数呢。。
// 他实际上又等价于 任意两点 点对的个数 也就是 C(n,2)







signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(15);
#ifdef DEBUG
	freopen("../1.in", "r", stdin);
#endif
	//init_f();
	//init();
	//expr();
	// int T; cin >> T; while(T--)
	solve();
	return 0;
}



  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
K-D Tree(K-Dimensional Tree)是一种用于处理 k 维空间数据的数据结构。它可以用于搜索最近邻点、范围搜索等问题。下面是一个简单的 Python 实现。 首先,我们需要一个节点类来表示树中的节点: ```python class Node: def __init__(self, point=None, axis=None, left=None, right=None): self.point = point # 节点代表的点 self.axis = axis # 划分轴 self.left = left # 左子树 self.right = right # 右子树 ``` 接下来,我们需要一个 `build_kdtree` 函数来构建 K-D Tree: ```python def build_kdtree(points, depth=0): n = len(points) if n <= 0: return None axis = depth % k # 选择轴 points.sort(key=lambda point: point[axis]) mid = n // 2 return Node( point=points[mid], axis=axis, left=build_kdtree(points[:mid], depth+1), right=build_kdtree(points[mid+1:], depth+1) ) ``` 这个函数会递归地将点集分成两部分,构建 K-D Tree。 接下来,我们需要实现两个重要的子函数:`nearest_neighbor` 和 `range_search`。 `nearest_neighbor` 函数用于查找 K-D Tree 中最近的点: ```python def nearest_neighbor(root, point): best = None best_distance = float("inf") def search(node, depth=0): nonlocal best, best_distance if node is None: return distance = euclidean_distance(point, node.point) if distance < best_distance: best = node.point best_distance = distance axis = depth % k if point[axis] < node.point[axis]: search(node.left, depth+1) if point[axis] + best_distance >= node.point[axis]: search(node.right, depth+1) else: search(node.right, depth+1) if point[axis] - best_distance <= node.point[axis]: search(node.left, depth+1) search(root) return best ``` 这个函数会从根节点开始递归地搜索 K-D Tree,找到与目标点最近的点。 最后,我们需要实现 `range_search` 函数来查找 K-D Tree 中给定范围内的所有点: ```python def range_search(root, lower, upper): result = [] def search(node, depth=0): if node is None: return if lower <= node.point <= upper: result.append(node.point) axis = depth % k if lower[axis] <= node.point[axis]: search(node.left, depth+1) if upper[axis] >= node.point[axis]: search(node.right, depth+1) search(root) return result ``` 这个函数会从根节点开始递归地搜索 K-D Tree,找到所有满足条件的点。 完整的代码如下所示: ```python import math k = 2 class Node: def __init__(self, point=None, axis=None, left=None, right=None): self.point = point # 节点代表的点 self.axis = axis # 划分轴 self.left = left # 左子树 self.right = right # 右子树 def euclidean_distance(p, q): return math.sqrt(sum((p[i] - q[i])**2 for i in range(k))) def build_kdtree(points, depth=0): n = len(points) if n <= 0: return None axis = depth % k # 选择轴 points.sort(key=lambda point: point[axis]) mid = n // 2 return Node( point=points[mid], axis=axis, left=build_kdtree(points[:mid], depth+1), right=build_kdtree(points[mid+1:], depth+1) ) def nearest_neighbor(root, point): best = None best_distance = float("inf") def search(node, depth=0): nonlocal best, best_distance if node is None: return distance = euclidean_distance(point, node.point) if distance < best_distance: best = node.point best_distance = distance axis = depth % k if point[axis] < node.point[axis]: search(node.left, depth+1) if point[axis] + best_distance >= node.point[axis]: search(node.right, depth+1) else: search(node.right, depth+1) if point[axis] - best_distance <= node.point[axis]: search(node.left, depth+1) search(root) return best def range_search(root, lower, upper): result = [] def search(node, depth=0): if node is None: return if lower <= node.point <= upper: result.append(node.point) axis = depth % k if lower[axis] <= node.point[axis]: search(node.left, depth+1) if upper[axis] >= node.point[axis]: search(node.right, depth+1) search(root) return result ``` 这是一个简单的 K-D Tree 的 Python 实现,可以用来解决搜索最近邻点、范围搜索等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值