[刷题之旅no20]P1131 [ZJOI2007] 时态同步

这道题,理解一下
每两个点之间的路径唯一,所以距离唯一
给定一个特定的结点,现在求解:怎么样加路径长度,使得当前结点到其他结点的路径相等(要求求最小值)
。。相当没有思路奥
我现在的思路:
相当空旷!
1.用什么数据结构(或者说怎么构建这个树)
如何建造这棵树呢?
问题:题目给出的是两个结点,和链接两个结点之间的通路
所以无法判断子父节点
如何判断子父节点?
激发点是1级结点
和1级结点相连的是2级结点
和2级结点相连的是3级结点
和同一个结点相连的是同一级结点
所以我就一遍遍遍历
用一个三维数组记录题目数据
然后第一遍,找两个结点,判断其中是否有一级点,有则另一个是2级点
有几级点则需要遍历多少次,而如果N等于50万,那么我光建造这个树就把时间都用光了

2.有了这个树之后如何求解?
我的:有了树之后的求解思路:
1.寻找最长路径值
2.增加其兄弟结点和父节点之间的路径长
3.计算非兄弟结点的路径长,从高级路径到低级路径进行加和。
也就是说
从上往下遍历结点
看每个结点对应子树和最大值之间差值的最小值
然后给这个结点加上相应最小值
记录改变后的对应子树的差值
然后继续向下层递归
最后把加上的值总和
需要一个递归函数,需要可靠的数据结构
tree(node结点,length上级节点加了多少权值)
{
length
node=node->chlid;
whlie(1)
{
tree(node,min(node,length));
if(node->next)//遍历兄弟结点
{
node=node->next;
}
else
{
break;
}
}
}
min(node(所要的父节点),length(激发点到此节点的路径长度)),求整个树之中以这个为父节点的子树和最大值相差的最小值
{

}
length(node)//求激发点到此节点的路径长度
{

}
伪代码和思路就这么多了,看答案喽!哈哈
看大神的思想:
1.种树的方法:
利用链式前向星对图进行记录
2.转化题目思想,保证所有子节点能够同时达到其父节点即可.
所以自下向上维护
函数需要参数(子节点编号,父结点编号)
遍历子节点和其子节点的连边
递归
遍历子节点和其子节点的连边
记录最大遍
遍历子节点和其子节点的连边
保证延长所有短边,保证和最大边一样长
对当前结点与其父节点之间的边进行更新
由于我们更新了当前结点和其子节点之间的最大值
所以为了和其同父兄弟结点更好的比较大小,我们需要公平竞技
也就是这个维护边长,是相当于当前结点到最底层节点的最大值。
所以需要让当前结点的父节点与当前节点的距离等于当前结点到最底层结点的最大值加上父节点到此节点的边长
然后这个再在这个父节点的孩子之中进行比较,取出最大值,然后把其他较小的边补齐就好了。
出现一点问题,遍历的时候i是变化的,所以需要edge[i]而不是edge[son]或者edge[father]
终于搞会了

#include<stdio.h>
typedef struct 
{
	int to,next,dis;
}Edge;
Edge edge[500005];
int cnt=0,n,origen;
int head[500005]={0};
int max_len[500005]={0};
long long ans=0;
void creategde(int from,int to,int dis)
{
	cnt++;
	edge[cnt].next=head[from];
	edge[cnt].to=to;
	edge[cnt].dis=dis;
	head[from]=cnt;
}
int max(int a,int b)
{
	return a>b?a:b;
}
void dfs(int s,int f)//深搜有点问题啊? 
{
	for(int i=head[s];i;i=edge[i].next)
	{
		if(edge[i].to!=f)
		{
			dfs(edge[i].to,s);
		}
	}
	for(int i=head[s];i;i=edge[i].next)
	{
		if(edge[i].to!=f)
		{
			max_len[s]=max(max_len[s],edge[i].dis);
		}
	}
	for(int i=head[s];i;i=edge[i].next)
	{
		if(edge[i].to!=f)
		{
			ans=ans+(max_len[s]-edge[i].dis);
		}
	}
	for(int i=head[f];i;i=edge[i].next)
	{
		if(edge[i].to==s)
		{
			edge[i].dis=edge[i].dis+max_len[s];
		}
	}
}
int main()
{
	int from,to,dis;
	scanf("%d %d",&n,&origen);
	for(int i=0;i<n-1;i++)
	{
		scanf("%d %d %d",&from,&to,&dis);
		creategde(from,to,dis);
		creategde(to,from,dis);
	}
	dfs(origen,0);
	printf("%lld",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值