首页 > 其他分享 >树的直径小记

树的直径小记

时间:2023-10-24 21:34:51浏览次数:37  
标签:en int sum 直径 小记 wz dis

我们总是在刷那些常考的算法,却忽略一些冷门算法,以至于一涉及这些就不会。
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)——题记

读本章所需思维:反证法

定义:树上任意两节点之间最长的简单路径即为树的「直径」

显然,一棵树可以有多条「直径」

一些引理(这里只讨论边权没有负的情况):

·\(1\),所有「直径」的中点是同一个

证明:考虑经过的不是同一点,那么一条「直径」的一端到该「直径」的中点再到另一个「直径」的中点再到另一个「直径」的一端一定更优,所以矛盾,古该结论成立。

·\(2\),从任意节点开始 \(dfs\),到达的最远节点,必然是直径的一端。

证明:考虑反证法,易证

1.1 试一试

观察题目,我们发现:要找长度和不超过 \(s\) 的路径,所以我们无法树形 \(DP\)(或者说很难)。

那竟然无法从条件入手,那就从目的入手:要求其他所有城市到这条路径的距离的最大值最小,所以我们要找这条路径的性质。

我们发现,这条路径必然包含一些点,因为到这些点最远的点就是树的「直径」的一端,所以我们找的点一定要尽可能接近树的「直径」的两端,所以可以得知这条路被树的「直径」包含。

因为「直径」有多条,考虑找任意一条即可,证明仔细思考即可,很难写

至于找路径可以用单调栈实现

上代码:

#include<bits/stdc++.h>
#define PII pair<int,int>
using namespace std;
const int N=3e5+50;
int n,s,ans=1e9;

int h[N],e[N*2],w[N*2],ne[N*2],idx;
void add(int a,int b,int c)
{
	e[idx]=b;
	w[idx]=c;
	ne[idx]=h[a];
	h[a]=idx++;
}

int dis[N],pre[N],xl[N];
void dfs(int wz,int last,int cd,bool flag)
{
	if(flag) pre[wz]=last,xl[wz]=cd;
	dis[wz]=dis[last]+cd;
	for(int i=h[wz];i!=-1;i=ne[i])
		if(e[i]!=last) dfs(e[i],wz,w[i],flag);
}
int st,en;
void Get_road()
{
	dfs(1,0,0,0);
	for(int i=1,maxdis=0;i<=n;i++)
		if(dis[i]>maxdis) maxdis=dis[i],st=i;
	dfs(st,0,0,1);
	for(int i=1,maxdis=0;i<=n;i++)
		if(dis[i]>maxdis) maxdis=dis[i],en=i;
}

int dis1[N];
void bfs()
{
	memset(dis,0x3f,sizeof dis);
	queue<int> q,from;
	for(int i=en;i!=0;i=pre[i])
		q.push(i),from.push(i),dis[i]=0;
	while(!q.empty())
	{
		int wz=q.front(),fr=from.front();
		q.pop(),from.pop();
		for(int i=h[wz];i!=-1;i=ne[i])
			if(dis[e[i]]==dis[0])
			{
				dis[e[i]]=dis[wz]+w[i];
				dis1[fr]=max(dis1[fr],dis[e[i]]);
				q.push(e[i]);
				from.push(fr);
			}
	}
}

PII que[N];
int sum[N],ks=1,js;
void solve()
{
	for(int i=en;i!=st;i=pre[i])//
		sum[pre[i]]=sum[i]+xl[i];
	for(int l=en,r=en;r!=st&&l!=0;l=pre[l])
	{
		int last=r;
		while(sum[r]-sum[l]<=s&&r!=0)
		{
			last=r,r=pre[r];
			if(r!=0&&sum[r]-sum[l]<=s)
			{
				while(js>=ks&&dis1[r]>=que[js].first) js--;
				que[++js]={dis1[r],r};
			}
		}
		if(r==0||sum[r]-sum[l]>s) r=last;
		int now=max(sum[l],sum[st]-sum[r]);
		now=max(now,que[ks].first);
		ans=min(now,ans);
		if(que[ks].second==l) ks++;
	}
}

int main()
{
	memset(h,-1,sizeof h);
	scanf("%d %d",&n,&s);
	int u,v,w;
	for(int i=1;i<n;i++)
	{
		scanf("%d %d %d",&u,&v,&w);
		add(u,v,w);
		add(v,u,w);
	}
	Get_road();
	bfs();
	solve();
	printf("%d\n",ans);
	return 0;
}

没有一个算法值得轻视,也没有一个算法简单
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)——后记

标签:en,int,sum,直径,小记,wz,dis
From: https://www.cnblogs.com/pengchujie/p/17785779.html

相关文章

  • <<Mysql是怎样运行的>>小记-2
    第十章:单表访问方法MysqlServer中又有一个叫优化器的模块,在Mysql服务端对一条查询语句进行语法解析之后,会将其再交给优化器来进行优化,在优化后会获得一个执行计划.这个执行计划中表明了应该使用哪些索引查询,还有表之间的连接顺序等等.最后会按照该执行计划中的步骤调用存......
  • 小记-忙不应该成为做不好某件事的借口
    我越来越忙了,领导选择把很多重要的事都放在我身上但是我以此为借口,经常偷闲,没有好好为自己的kpi忙碌,很有可能导致年终奖不理想,甚至可能导致职级晋升出问题,以后应分清主次。另,今天在向没给我提供重要资料的技服人员发脾气之后深有感触。工作,大可不必如此伤神动气。在恋爱中,不应......
  • 树的直径、重心、中心
    树的直径、重心、中心一、树的直径我们将一棵树\(T=(V,E)\)的直径定义为$max(u,v)(u,v∈V)$,即树中所有最短路径距离的最大值即为树的直径。求法:1)树形dp定义d1为从节点u到其子树中节点距离的最大值,d2为次大值,则\(diameter=max(d1+d2)\)特点:不可输出路径,但可以处理负边......
  • 10.18 模拟赛小记
    这下真的寄了。赛前多校联测2。胜利一中出题。比赛链接。官方题解。A.谁共一杯芳酒赛时写了个小范围的爆搜和假的贪心。赛后一想笑的我。好好好。有的样例。给了和没给有什么区别啊。真无语。正确的思路是先按照一边端点为关键字排序,另一边按照最长不下降序列处理。这......
  • SpringBoot 注解小记
    用于入口类的注解SpringBootApplication标识该类是入口ComponentScan表示扫描入口类同级和所有子包下的Component我们也可以使用ComponentScan("Com.XXXX")自定义扫描路径用于类的注解@Component,@Service,@Repository,@Controller四个注解用于类上,后三个实质上都是Compon......
  • 「Log」2023.10.17 小记
    CSP第二轮倒数\(3\)天。序幕\(\text{6:40}\):到校,整理博客。\(\text{7:30}\):模拟赛发题。题意都很简单,感觉都是很怪异的配置,T1性质是显著的,一会就切了。T3感觉不知道想考啥,反手扔个乱搞。T2T4是一点思路没有,T4连暴力都不会,应该涉及到切比雪夫距离性质啥的。被创死了......
  • 10.17 小记录
    linktoproblem记录原因:自己做法代码长度太长。自己的做法:linktosubmission离线下来,离散化。题目是要求连续段的个数。Subtask$2$的做法考虑从大到小一个一个加入数。加入一个数的时候如果两边没有,答案加一;有一个,不变;都有,减一。预处理完\(O(1)\)一个询问。考虑先......
  • 10.16 模拟赛小记
    比赛链接A.link徐爷爷很强的用线段树切了,orz。正解大概是树形dp但是有O(1)的解法没想到吧...?咕咕了,还不会。B.link赛时只会写30pts的暴力,感觉成飞舞了。C.link先写了一个二维\(n^2\)的暴力dp。根据式子就可以优化掉一层循环,然后\(O(n*a[i])\)就有60pts的好......
  • Perceptual Losses 风格迁移论文复现小记
    看了一篇李飞飞组的论文PerceptualLossesforReal-TimeStyleTransferandSuper-Resolution。论文地址为:https://arxiv.org/pdf/1603.08155.pdf))想去找找代码复现一下。原文没有提供代码,就只有找找别人按照论文细节实现的代码。不过但是论文是2016年的,距离现在2023年已经......
  • 10.14 模拟赛小记
    传送门感觉我已经是半个废人了。A.P1118[USACO06FEB]BackwardDigitSumsG想到的是预处理杨辉三角,然后dfs找。我的预处理写的三维。原因是听大家打键盘的声音太吵了(指机械键盘),然后就不会写二维的了。然后只会写三维的。然后就被同学嘲讽为什么不写二维的。据说next_pe......