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;
}
希望能帮助到大家!