P4220 题解

前言

题目传送门!

更好的阅读体验?

思路

首先随便找一个点作为根。

类似于找直径,Dfs 一下,找到距离这个点权值最远的一个点。

记录一下这个权值,它有可能成为答案。

然后再用这个点作为新的根,再搜索。可以多来几次。

快超时了就输出答案,退出程序。

注意所有检验的根都不能重复,这样效率会更高。

然后就过了!

代码

#include <iostream>
#include <cstdio>
#include <ctime>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
struct G {
	struct Edge {int now, nxt; ll w;} e[N << 1];
	int head[N], cur;
	void add(int u, int v, ll w)
	{
		e[++cur].now = v, e[cur].nxt = head[u], e[cur].w = w;
		head[u] = cur;
	}
} g[3];
bool vis[N]; ll dis[3][N];
void dfs(int u, int fa, int idx) //暴力地遍历
{
	for (int i = g[idx].head[u]; i; i = g[idx].e[i].nxt)
	{
		int v = g[idx].e[i].now; ll w = g[idx].e[i].w;
		if (v == fa) continue;
		dis[idx][v] = dis[idx][u] + w, dfs(v, u, idx);
	}
}
int main()
{
	unsigned int seed = 0; //膜拜zlt的
	for (char c : "zlt is good at AK IOI") seed *= c;
	srand(seed);
	
	int n;
	scanf("%d", &n);
	for (int k = 0; k < 3; k++)
		for (int i = 1; i < n; i++)
		{
			int u, v; ll w;
			scanf("%d%d%lld", &u, &v, &w);
			g[k].add(u, v, w), g[k].add(v, u, w);
		}
	double st = clock(); ll ans = 0;
	while ("zlt txdy txdy txdy txdy") //膜拜zlt的,等同于 while(true)
	{
		int root;
		do //乱找一个没有检验过的根
		{
			root = rand() % n + 1;
			if ((clock() - st) / CLOCKS_PER_SEC >= 3.5) cout << ans, exit(0); //快超时了结束程序
		} while (vis[root]);
		
		int T = rand() % 5 + 10; //随机一个检验次数
		while (T--) //随便地暴力
		{
			if (vis[root]) break;
			vis[root] = true;
			for (int i = 0; i < 3; i++) dis[i][root] = 0, dfs(root, -114514, i);
			ll maxn = 0;
			for (int u = 1; u <= n; u++)
			{
				ll w = dis[0][u] + dis[1][u] + dis[2][u];
				if (!vis[u] && w > maxn) maxn = w, root = u;
				ans = max(ans, w);
			}
		}
	}
	cout << ans;
	return 0;
}

希望能帮助到大家!

posted @ 2023-01-14 15:20  liangbowen  阅读(20)  评论(0编辑  收藏  举报