[BZOJ2870]最长道路tree

written on 2022-07-10

超链接:无,可百度。

补一下之前比赛的题目。

题目要求树上点对,很容易想到用点分治,但是这个怎么维护我不会于是搁着了。(待更新)

事实上,这题还有一个很明显的特征,也就是最小值。虽然它与链长相结合,但是根据最小值我们仍然可以考虑离线的做法,也就是枚举每一个最小值,然后统计联通的最长路径。

那么这样一来题目的做法就显然了。先按点的权值排序,然后从大到小加点,每一次找出目前存在点集中与当前枚举的点相连的点构成的联通块的最大链长。那么这里,我们就要考虑与直径计算方式相关的一个引理:

  • 合并两个联通块,其中最长链一定在原先的分别两个端点,即共四个端点(2×2=4)中经过排列的某一种方案中。

那么这样我们就可以用并查集维护联通性,然后直接加点更新答案即可。

于是此题获解。点分治等其他解法以后有空更新。

最后记得开 long long

难得的一遍过的题目/dk

#include<bits/stdc++.h>
#define N 50005
using namespace std;
int n;
int tot,ver[N<<1],nxt[N<<1],head[N];
void add_E(int x,int y){ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;}
int fa[N];
int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);}
int f[N][17],dep[N];
int lca(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=16;i>=0;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
	if(x==y) return x;
	for(int i=16;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0];
}
void dfs(int x)
{
	for(int i=1;i<=16;i++) f[x][i]=f[f[x][i-1]][i-1];
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];
		if(y==f[x][0]) continue;
		f[y][0]=x,dep[y]=dep[x]+1;
		dfs(y);
	}
}
int dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)]+1;}
int L[N],R[N];
struct F{int x,v;}a[N];
bool cmp(F a,F b){return a.v>b.v;}
typedef long long ll;
ll ans;
bool vis[N];
void work(int id)
{
	int v=a[id].v,x=a[id].x;
	vis[x]=1;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];
		if(!vis[y]) continue;
		int fx=get(x),fy=get(y);
		if(fx==fy) continue;
		//merge(x,y),update L,R
		int t1=L[fx],t2=L[fy],t3=R[fx],t4=R[fy];
		fa[fy]=fx;
		int d12=dis(t1,t2),d13=dis(t1,t3),d14=dis(t1,t4),d23=dis(t2,t3),d24=dis(t2,t4),d34=dis(t3,t4);
		int mx=max(d12,max(d13,max(d14,max(d23,max(d24,d34)))));
		if(d12==mx) L[fx]=t1,R[fx]=t2;
		else if(d13==mx) L[fx]=t1,R[fx]=t3;
		else if(d14==mx) L[fx]=t1,R[fx]=t4;
		else if(d23==mx) L[fx]=t2,R[fx]=t3;
		else if(d24==mx) L[fx]=t2,R[fx]=t4;
		else if(d34==mx) L[fx]=t3,R[fx]=t4;
	}
	int fx=get(x);
	ans=max(ans,1ll*v*dis(L[fx],R[fx]));
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i].v),a[i].x=i,fa[i]=i,L[i]=R[i]=i;
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add_E(x,y),add_E(y,x);
	}
	dfs(1);
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++) work(i);
	printf("%lld\n",ans);
}
posted @   Freshair_qprt  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示