NOIP 2015 运输计划

2 篇文章 0 订阅
1 篇文章 0 订阅

题目描述:

给你一棵n个点的带权无根树和m条树上两点之间的路径,你可以将树上任意两个直接相连的点之间的路径变成权值为0,并尽可能使得改变后路径长度的最大值最小,输出这个最大值。

数据范围如下:


20%解法(测试点1-4):

十分暴力的做法:枚举改哪条边,然后对于每一条路径都暴力在原图上搜索一遍,求出长度,所有长度求个max,然后对所有修改方案求个min即可。时间复杂度:

50%-60%解法(测试点1-12,但测试点9,10有些写的丑的可能卡T):

依然是枚举修改的边,但是考虑在30分做法求路径长的方法上进行改进,每枚举一条边就重新建一棵树,固定1节点为根,并重造倍增lca的数组,同时每个点记录从这点到根的距离dis【i】,考虑一个从u节点到v节点的路径,它的长度就是dis【u】+dis【v】-2dis【lca(u,v)】。时间复杂度:

95%-100%解法:

我们可以发现如果输出的答案为ans,那么修改的边必然被输入路径中原长为ans+1到max的路径覆盖。这样我们发现只需要二分答案,然后把比这个答案长的路径在树上做一次差分,然后dfs一遍原图,去除被这些所有路径覆盖的最长边,假设最长边长度为len,原路径最长为max,二分判断的路径长为mid,如果max-len>mid则说明ans要比mid大否则就小于等于mid。具体操作样例说话:

6  3

1  2  3

1  6  4

3  1  7

4  3  6

3  5  5

3  6

2  5

4  5

建出如下树:


然后将路径长度排序,第一条长度为11,第二条长度为10,第3条长度为11,然后把比二分的mid大的路径全部差分:

差分具体操作:一开始所有点权为0,当处理到u与v之间的路径时,在u节点点权+1,v节点点权+1,lca(u,v)节点点权-2。那么处理完路径长大于mid的路径后再dfs一遍,每个节点的子树权值之和就是这个节点连向父亲的边被覆盖的路径数。例如求每条边被这3条路径覆盖了多少次:

首先算第一条路径,从3到6,那么节点3,6点权+1,节点1点权-2。(橙色的数表示节点权值)


于是节点的权值变成了这样:


第二条路径,节点2,3点权+1,节点1点权-2。


变成这样:


第三条路径,节点4,5点权+1,节点3点权-2。


变成这样:


dfs求一遍每个节点的子树点权之和,就是这个节点连向父亲的边的被覆盖的路径数啦!

(紫色为每个节点的子树点权和)


这样差分就完成了,剩下的就是简单的操作:把被所有长度大于mid的路径覆盖的边求一个最大边权len。如果max-len>mid;则可以判断ans>mid否则ans<=mid(其中max为原图最长路径,mid为二分判断的答案,ans为最后输出的答案)。

这题用倍增求lca是的复杂度,会T掉最后一个点,所以应该用欧拉序求lca,查询一次lca是O(1)的复杂度,预处理欧拉序lca是的,每次二分+差分+dfs时间复杂度是时间复杂度就可以降到的复杂度,可以过100%的数据,这就是95分和100分的小区别(当年NOIP很多这题都是95分的)。

                               

                                                           推荐番:《某科学的超电磁炮》

上代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
struct data
{int u,v,len;};
data a[300010];
int dfn,pan[600010],to[600010],pp[600010],next[600010],line[600010],fir[600010],zhi[600010],val[600010];
int rmq[600010][23],lcc[600010][23],dep[600010],dui[600010],n,m,x,y,v,p,u,gen[600010];
int qian[600010],bian,chafen[600010],ma,l,r,mid;
bool cmp(data a,data b)
{
	return a.len<b.len;
}
void dfs(int k)
{
	pan[k]=1;
	dfn++;line[dfn]=k;fir[k]=dfn;
	int pu=pp[k];
	while (pu>0)
	{
		if (pan[to[pu]]==0)
		{
			gen[to[pu]]=gen[k]+val[pu];
			zhi[to[pu]]=val[pu];
			dep[to[pu]]=dep[k]+1;
			dfs(to[pu]);
			dfn++;line[dfn]=k;
		}
		pu=next[pu];
	}
}
void dfs2(int k,int zz)
{
	pan[k]=1;
	int pu=pp[k];
	qian[k]=chafen[k];
	while (pu>0)
	{
		if (pan[to[pu]]==0)
		{
			dfs2(to[pu],zz);
			qian[k]+=qian[to[pu]];
		}
		pu=next[pu];
	}
	if (qian[k]==zz){bian=max(bian,zhi[k]);}
}
void rr()
{
	for (int i=1;i<=dfn;i++){rmq[i][0]=dep[line[i]];lcc[i][0]=line[i];}
	for (int i=1;(1 << i)<=dfn;i++)
	{
		for (int j=1;j<=dfn;j++)
		{
			if (rmq[j][i-1]<rmq[j+(1 << (i-1))][i-1])
			{
			   rmq[j][i]=rmq[j][i-1];
			   lcc[j][i]=lcc[j][i-1];	
			}
			else
			{
			   rmq[j][i]=rmq[j+(1 << (i-1))][i-1];
			   lcc[j][i]=lcc[j+(1 << (i-1))][i-1];	
			}
		}
	}
	int po=2;
	for (int i=2;i<=dfn;i++)
	{
		if (i==po){po*=2;dui[i]=dui[i-1]+1;}
		else dui[i]=dui[i-1];
	}
}
int lca (int u,int v)
{
	if (fir[u]>fir[v])swap(u,v);
	int er=dui[fir[v]-fir[u]+1];
    if (rmq[fir[u]][er]<rmq[fir[v]-(1 << er)+1][er])return lcc[fir[u]][er];
    else return lcc[fir[v]-(1 << er)+1][er];
}
bool check(int ll)
{
	int lef=0,rig=m+1,mm;
	while (lef+1<rig)
	{
		mm=(lef+rig)/2;
		if (a[mm].len>ll)rig=mm;
		else lef=mm;
	}
	if (a[lef].len<=ll)lef++;
	for (int i=1;i<=n;i++)chafen[i]=0;
	for (int i=lef;i<=m;i++)
	{
		chafen[a[i].u]++;chafen[a[i].v]++;
		chafen[lca(a[i].v,a[i].u)]-=2;
	}
	bian=0;
	for (int i=1;i<=n;i++){pan[i]=0;qian[i]=0;}
	dfs2(1,m-lef+1);
	if (ma-bian<=ll)return true;
	return false;
}
int main()
{
	cin>>n>>m;
	for (int i=1;i<n;i++)
	{
		 scanf("%d %d %d",&x,&y,&v);
		 p++;to[p]=y;val[p]=v;next[p]=pp[x];pp[x]=p;
		 p++;to[p]=x;val[p]=v;next[p]=pp[y];pp[y]=p;
	}
	dep[1]=1;
	dfs(1);
	rr();
	for (int i=1;i<=m;i++)
	{
		scanf("%d %d",&a[i].u,&a[i].v);
		a[i].len=gen[a[i].u]+gen[a[i].v]-2*(gen[lca(a[i].u,a[i].v)]);	
		ma=max(ma,a[i].len);	
	}
	sort(a+1,a+1+m,cmp);
	l=-1;r=ma+1;
	while (l+1<r)
	{
		mid=(l+r)/2;
		if (check(mid))r=mid;
		else l=mid;
	}
	printf("%d\n",r);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值