luoguP4220 [WC2018]通道 随机化
有一个非常暴力的做法:枚举 $u,v$ 两点中的一个点作为根,然后在 3 棵树中以这个点为根 DFS 一遍,求最大值.
然后考虑用随机化去骗分:设当前枚举的点为 $x$,下一个点 $y$ 可以是 $x$ 为根时求出的最优解.
然后每隔 8 到 9 次随机一个新的 $x$.
code:
#include <bits/stdc++.h> #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; const int N=200006; int n; struct Graph { ll val[N<<1],dep[N<<1]; int hd[N],to[N<<1],nex[N<<1],edges; void add(int u,int v,ll c) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; } void dfs(int x,int ff) { for(int i=hd[x];i;i=nex[i]) { int y=to[i]; if(y==ff) continue; dep[y]=dep[x]+val[i],dfs(y,x); } } void DFS(int x) { dep[x]=0,dfs(x,0); } }gr[3]; namespace brute { int main() { ll ans=0; for(int i=1;i<=n;++i) { for(int j=0;j<3;++j) gr[j].DFS(i); for(int j=1;j<=n;++j) ans=max(ans,gr[0].dep[j]+gr[1].dep[j]+gr[2].dep[j]); } printf("%lld\n",ans); return 0; } }; int vis[N]; int main() { // setIO("input"); srand(time(NULL)); scanf("%d",&n); for(int j=0;j<3;++j) { for(int i=1;i<n;++i) { ll c; int a,b; scanf("%d%d%lld",&a,&b,&c); gr[j].add(a,b,c); gr[j].add(b,a,c); } } int po=rand(); ll ans=0; if(n<=5000) brute::main(); else { for(int i=0;i<10;++i) { ll tmp=0; int u=rand()%n+1,id=0; while(vis[u]) u=rand()%n+1; for(int j=0;j<10;++j) { vis[u]=1; gr[0].DFS(u); gr[1].DFS(u); gr[2].DFS(u); for(int k=1;k<=n;++k) { if(gr[0].dep[k]+gr[1].dep[k]+gr[2].dep[k]>tmp) { tmp=gr[0].dep[k]+gr[1].dep[k]+gr[2].dep[k]; id=k; } } ans=max(ans,tmp),u=id; while(vis[u]) u=rand()%n+1; } } printf("%lld\n",ans); } return 0; }