【NOIP2015模拟11.5】旅行

Description在这里插入图片描述

Solution

经过观察,可以发现题目有一个比较不错的性质:

1、一条合法的路径必须由两条路径组成,一条是奇数,另一条是偶数。

所以我们可以先把每一个点到达根节点的路径求出来,深度为奇数的点放进一个 a a 数组里,偶数的放进 b b 数组里,再给他们分别进行排序。
然后进行两两结合,先把a数组里的所有数跟 b 1 b_{1} 结合,把路径丢进一个小根队里。每次取出堆顶,假设取出来的是 a i a_{i} b j b_{j} ,那么我们就把 a i a_{i} b j + 1 b_{j+1} 丢进堆里,第 k k 次取出来的堆顶就是答案。
可是还是有很多童鞋有疑惑:两个路径结合,他们可能会有重合的边呀?
答:但是两条路径的深度的奇偶性质并不相同,所以呢两个路径重合的部分,第一条路径是正数,第二条路径就是负数,反之,第一条路径是负数,第二条路径是正数,所以两两会抵消掉,这样我们就不用考虑了。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,m,cnt,tot,tot1=1,num;
int head[N],dep[N];
ll dis[N],heap[N][3],a[N],b[N];
struct node {
	int to,next;
	ll len;
}edge[N<<1];
void add(int x,int y,ll z) {
	edge[cnt].to=y;
	edge[cnt].len=z;
	edge[cnt].next=head[x];
	head[x]=cnt++;
}
void dfs(int now,int fa) {
	for(register int i=head[now];i!=-1;i=edge[i].next) {
		int son=edge[i].to;
		ll len=edge[i].len;
		if(son==fa)continue;
		dep[son]=dep[now]+1;
		dis[son]=-dis[now]+len;
		if(dep[son]&1)a[++tot]=dis[son];
		else b[++tot1]=dis[son];
		dfs(son,now);
	}
}
void Swap(int x,int y) {
	swap(heap[x][0],heap[y][0]);
	swap(heap[x][1],heap[y][1]);
	swap(heap[x][2],heap[y][2]);
}
void up(int x) {
	while(x>1&&heap[x][0]<heap[x>>1][0])
		Swap(x,x>>1),x>>=1;
}
void down(int x) {
	while(((x<<1)<=num&&heap[x][0]>heap[x<<1][0])||(((x<<1)|1)<=num&&heap[x][0]>heap[(x<<1)|1][0])) {
		int y=x<<1;
		if((y|1)<=num&&heap[y][0]>heap[y|1][0])y|=1;
		Swap(x,y);
		x=y;
	}
}
int main() {
	freopen("travel.in","r",stdin);
	freopen("travel.out","w",stdout);
	scanf("%d%d",&n,&m);
	memset(head,-1,sizeof(head));
	for(register int i=1;i<n;i++) {
		int u,v;ll w;
		scanf("%d%d%lld",&u,&v,&w);
		add(u,v,w);add(v,u,w);
	}
	b[1]=0;dep[0]=-1;
	dfs(1,0);
	sort(a+1,a+1+tot);
	sort(b+1,b+1+tot1);
	for(register int i=1;i<=tot;i++) {
		heap[i][0]=a[i]+b[1];
		heap[i][1]=i;heap[i][2]=1;
	}
	num=tot;
	for(register int i=1;i<m;i++) {
		if(!num) {
			puts("Stupid Mike");
			return 0;
		}
		int x=heap[1][1],y=heap[1][2];
		Swap(1,num);
		--num;down(1);
		if(y+1<=tot1) {
			heap[++num][0]=a[x]+b[y+1];
			heap[num][1]=x;heap[num][2]=y+1;
			up(num);
		}
	}
	printf("%lld",heap[1][0]);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/MZHjr/article/details/107823809
今日推荐