洛谷 P3304 [SDOI2013] 直径 题解

这篇具有很好参考价值的文章主要介绍了洛谷 P3304 [SDOI2013] 直径 题解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

洛谷 P3304 [SDOI2013] 直径 题解

题目链接

题目分析

第一部分好说,求直径,dfs或者DP都可以。

第二部分,有一个定理,就是所有直径中点重叠。

那么有两种情况

  • 一种是中点在一个节点上,那么显然这个点是每条直径的终点,也就是说直径的一半相等。从这个点出发dfs,找出所有最远点。如果只有两条,输出depth之和。否则求lca,lca的depth就是重叠的数量。

  • 另一种,中点在一条边上。从这个边出发,两侧分别dfs找最远,再分类讨论,有的求lca,有的输出。具体见代码即可。

题解中还有其他思路:比如从一条直径上开始dfs(利用直径同侧长度一定相等的性质),还有两次dp求出总cnt和边cnt进行统计的,还有去掉中点所在边之后进行RootLeafPath的。这些思路都很有用。

顺便提一句,在题解里面看到了专门用结构体Data来统计数据(维护最大值和出现次数)以及通过左右分开上升最大值来排除自身这两个trick,觉得十分好用。文章来源地址https://www.toymoban.com/news/detail-630900.html


代码

#include <bits/stdc++.h>

#define N (long long)(200000 + 5)
#define LOGN (long long)(25)

using namespace std;

typedef long long LL;

struct node
{
	LL v, w, next;
}e[N * 2];

LL n;

LL head[N];
LL cnt;

LL d1[N],d2[N];
LL k1[N],k2[N];
LL d,o;
bool vis[N];//

void adde(int u, int v, int w)
{
	cnt++;
	e[cnt].v = v;
	e[cnt].w = w;
	e[cnt].next = head[u];
	head[u] = cnt;
}

void dpdfs(int p)
{
	vis[p] = true;
	d1[p] = d2[p] = 0;
	k1[p] = k2[p] = 0;
	for(int i = head[p];i != 0;i = e[i].next)
	{
		if(!vis[e[i].v])
		{
			vis[e[i].v] = true;
			dpdfs(e[i].v);
			if(d1[e[i].v] + e[i].w > d1[p])
			{
				d2[p] = d1[p];
				k2[p] = k1[p];
				d1[p] = d1[e[i].v] + e[i].w;
				k1[p] = e[i].v;
			}
			else if(d1[e[i].v] + e[i].w > d2[p])//
			{
				d2[p] = d1[e[i].v] + e[i].w;
				k2[p] = e[i].v;
			}
		}
	}
	if(d2[p] + d1[p] > d)
	{
		d = d2[p] + d1[p];
		o = p;
	}
	vis[p] = false;
}

LL depth[N];
LL len[N];
LL maxlendep1;
LL maxlendep2;
LL maxlen1;
LL maxlen2;
LL maxlenidx1[N];
LL maxlenidx2[N];
LL maxlencnt1;
LL maxlencnt2;

void deepdfs(int p,LL *mxi,LL &mxc,LL &mxl, LL &mxd)
{
	vis[p] = true;
	for(int i = head[p];i != 0;i = e[i].next)
	{
		if(!vis[e[i].v])
		{
			vis[e[i].v] = true;
			depth[e[i].v] = depth[p] + 1;
			len[e[i].v] = len[p] + e[i].w;
			if(mxl < len[e[i].v])
			{
				mxl = len[e[i].v];
				mxd = depth[e[i].v];
				mxc = 1;
				mxi[mxc] = e[i].v;
			}
			else if(mxl == len[e[i].v])
			{
				mxi[++mxc] = e[i].v;
			}
			deepdfs(e[i].v,mxi,mxc,mxl,mxd);
		}
	}
	vis[p] = false;
}

int lcadepth[N];
int fa[N][LOGN];

void lcadfs(int p)
{
	vis[p] = true;
	for(int i = head[p];i != 0;i = e[i].next)
	{
		if(!vis[e[i].v])
		{
			vis[e[i].v] = true;
			lcadepth[e[i].v] = lcadepth[p] + 1;
			fa[e[i].v][0] = p;
			for(int j = 1;j <= log2(n);j++)
				fa[e[i].v][j] = fa[fa[e[i].v][j - 1]][j - 1];
			
			lcadfs(e[i].v);
		}
	}
	vis[p] = false;
}

int lca(int x, int y)
{
	if(lcadepth[y] > lcadepth[x])
		swap(x,y);
	for(int i = log2(n); i >= 0;i--)
		if(lcadepth[fa[x][i]] >= lcadepth[y])
		{
			x = fa[x][i];
		}
			
	if(x == y) return x;
	for(int i = log2(n);i >= 0;i--)
		if(fa[x][i] != fa[y][i])
		{
			x = fa[x][i];
			y = fa[y][i];
		}
	return fa[x][0];
}


int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin >> n;
	for(int i = 1;i <= n - 1;i++)
	{
		int u,v,w;
		cin >> u >> v >> w;
		adde(u,v,w);
		adde(v,u,w);
	}
	dpdfs(1);
	cout << d << "\n";
	LL idx = o, lidx = idx;
	LL deep = 0;
	while(idx != 0)
	{
		if(deep + d2[o] >= d / 2)
		{
			if(((d % 2) == 0) && ((deep + d2[o]) == (d / 2)))
			{
				lidx = idx;
			}
			break;
		}
		lidx = idx;
		idx = k1[idx];
		deep += d1[lidx] - d1[idx];
	}
	
	if(idx != lidx)
	{
		vis[lidx] = true;
		depth[idx] = 0;
		len[idx] = 0;
		deepdfs(idx,maxlenidx1,maxlencnt1,maxlen1,maxlendep1);
		vis[lidx] = false;
		
		
		vis[idx] = true;
		depth[lidx] = 0;
		len[lidx] = 0;
		deepdfs(lidx,maxlenidx2,maxlencnt2,maxlen2,maxlendep2);
		vis[idx] = false;

		lcadepth[0] = -1;
		lcadfs(idx);
		int lca1 = 0, lca2 = 0;
		if(maxlencnt1 >= 1)
		{
			lca1 = maxlenidx1[1];
			for(int i = 2;i <= maxlencnt1;i++)
			{
				lca1 = lca(lca1,maxlenidx1[i]);
			}
		}
		if(maxlencnt2 >= 1)
		{
			lca2 = maxlenidx2[1];
			for(int i = 2;i <= maxlencnt2;i++)
			{
				lca2 = lca(lca2,maxlenidx2[i]);
			}	
		}
		
		
		int cnt1 = maxlencnt1, cnt2 = maxlencnt2;
		
		if(cnt1 == 1 && cnt2 == 0) cout << maxlendep1 + 1 << "\n";
		if(cnt1 == 0 && cnt2 == 1) cout << maxlendep2 + 1 << "\n";
		if(cnt1 == 2 && cnt2 == 0) cout << depth[lca1] + 1 << "\n";
		if(cnt1 == 1 && cnt2 == 1) cout << maxlendep1 + maxlendep2 << "\n";
		if(cnt1 == 0 && cnt2 == 2) cout << depth[lca2] + 1 << "\n";
		if(cnt1 >= 2 && cnt2 == 1) cout << depth[lca1] + maxlendep2 + 1 << "\n";
		if(cnt1 == 1 && cnt2 >= 2) cout << maxlendep1 + depth[lca2] + 1 << "\n";
		if(cnt1 >= 2 && cnt2 >= 2) cout << depth[lca1] + 1 + depth[lca2] << "\n";
	}
	else
	{
		vis[idx] = true;
		depth[idx] = 0;
		len[idx] = 0;
		deepdfs(idx,maxlenidx1,maxlencnt1,maxlen1,maxlendep1);
		vis[idx] = false;
		
		lcadepth[0] = -1;
		lcadfs(idx);
		int lca1 = 0;
		if(maxlencnt1 >= 1)
		{
			lca1 = maxlenidx1[1];
			for(int i = 2;i <= maxlencnt1;i++)
			{
				lca1 = lca(lca1,maxlenidx1[i]);
			}
		}
		
		if(maxlencnt1 == 2) cout << depth[maxlenidx1[1]] + depth[maxlenidx1[2]] << "\n";
		else cout << depth[lca1] << "\n";
		
	}
	return 0;
}
/*
6
3  1 80
1  4 10
4  2 70
4  5 50
4  6 90
*/

/*
6
1 2 1
2 3 4
2 4 3
1 6 2
1 5 3
*/

到了这里,关于洛谷 P3304 [SDOI2013] 直径 题解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 洛谷P1249题解

    一个正整数一般可以分为几个互不相同的自然数的和,如 3 = 1 + 2 3=1+2 3 = 1 + 2 , 4 = 1 + 3 4=1+3 4 = 1 + 3 , 5 = 1 + 4 = 2 + 3 5=1+4=2+3 5 = 1 + 4 = 2 + 3 , 6 = 1 + 5 = 2 + 4 6=1+5=2+4 6 = 1 + 5 = 2 + 4 。 现在你的任务是将指定的正整数 n n n 分解成若干个互不相同的自然数的和,且使这些自

    2024年02月05日
    浏览(51)
  • P6818 [PA2013]Działka 题解

    我太菜了。。。。 对着 jiangly 大佬的题解研究了一下午研究了一下午才搞出来(泪目。 作为一个蒟蒻,我就详细的讲一下我对与本题的理解。 本题的的题意描述的还是比较明了。 在二维坐标系中,输入 (n) 个点 (m) 次询问, 每次询问,给出一个矩阵, 求出矩阵内极大凸

    2024年02月01日
    浏览(29)
  • 洛谷 CF1743APassword 题解

    https://www.luogu.com.cn/problem/CF1743A 已知一个长度为四的,只包含字符 0 , 1 , 2 , … , 9 0,1,2,dots ,9 0 , 1 , 2 , … , 9 的字符串中不会出现哪些字符,求可能的字符串的数量。 Monocarp has forgotten the password to his mobile phone. The password consists of $ 4 $ digits from $ 0 $ to $ 9 $ (note that it can start wit

    2023年04月20日
    浏览(46)
  • 洛谷AT4888 题解-伦伦数

    A positive integer XX is said to be a lunlun number if and only if the following condition is satisfied: In the base ten representation of XX (without leading zeros), for every pair of two adjacent digits, the absolute difference of those digits is at most 11 . For example, 12341234 , 11 , and 334334 are lunlun numbers, while none of 3141531415 

    2024年02月06日
    浏览(52)
  • 洛谷 P1336 最佳课题选择 题解

    题目链接 状态:考虑 (f_{i,j}) 表示前 (i) 种论文里面,一共写了 (j) 篇,的最少花费时间。 转移策略:我们一次考虑每一种论文写多少篇。假设写 (k) 篇, (k in [0,j] cap mathbb{Z}) ,有转移方程: [f_{i,j} = min(f_{i-1,j-k} + text{cost}(i,k)), k in [0,j] cap mathbb{Z}] 其中 [text{

    2024年02月14日
    浏览(37)
  • 洛谷 P1122 最大子树和 题解

    一道入门的树形DP。 首先我们对于数据进行有序化处理,这便于我们利用数据结构特点(可排序性)来发觉数据性质(有序、单调、子问题等等性质),以便于后续的转化、推理和处理。 有序化可以“转化和创造”性质 首先将视角从无根树切换为有根树,这样我们就可以得

    2024年02月17日
    浏览(36)
  • 洛谷 U123017 机器人题解

    机器人会按照输入的指令进行移动,命令包括’E’,‘S’,‘W’,\\\'N’四种,分别对应东南西北。执行某个命令时它会消耗1秒钟向对应的方向移动一格单位。 在0时刻机器人位于(0,0)。 如果遇到’E’命令,向右一个单位,即到达(1,0)。如果遇到’S’命令,向下一个单位,即到达

    2024年03月21日
    浏览(43)
  • 【洛谷题解】B2010 带余除法

    题目链接:带余除法 - 洛谷 题目难度:入门 涉及知识点:除法,计算余数 题意: 分析:计算商后再用a/商*b得余数 AC代码: 总结:计算商后再用a/商*b得余数

    2024年02月19日
    浏览(36)
  • 洛谷 P1387 最大正方形 题解

    通过二维前缀和判定矩形内是否全为1,计算和等于长度的平方就判断为是 复杂度 (Theta (n^2log{n})) 设状态 (f_{i,j}) 为以第 (i) 行 (j) 列为右下角的最大正方形的边长, (a_{i,j}) 表示输入矩阵中的数值,有转移方程: [f_{i,j} = (min(f_{i-1,j},f_{i,j-1},f_{i-1,j-1}) + 1) * a_{i,j}] 解释:

    2024年02月16日
    浏览(44)
  • 洛谷 P1379 八数码难题 A* 题解

    刚做完一道模板A*,看到这题我直接小脑萎缩了... 阿米诺斯!这怎么用A*?!——刚开题的我 beeeeeeeeee like 甚至比模板简单(这是绿的...) 其实会是会但是纸张的是这玩意我不会搞估价函数我草! 然后突然想到能不能把这个状态下有多少个数字不在目标位置作为估价函数?

    2024年03月22日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包