#二叉堆#JZOJ 4320 旅行


分析

有一个很重要的性质就是如果经过道路数为奇数,把两个点到根节点的路径长加起来就是两个点间的路径长(正负消掉了)
而且众所周知的是奇数+偶数=奇数
可以预处理每个点到根节点的路径长度(按照题目要求)
然后把\(n\)个点分成深度为奇数和偶数两个部分,
那就可以套洛谷 1631 序列合并


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=100011; typedef long long lll;
struct node{int y,w,next;}e[N<<1];
struct rec{
    int rk1,rk2;
	lll w;
	bool operator <(const rec &t)const{
		return w<t.w;
	}
}heap[N];
lll odd[N],even[N],dis[N],ans;
int m,cnt,dep[N],n1,n2,as[N],n,k=1;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans; 
}
inline void Swap(rec &t1,rec &t2){rr rec t=t1; t1=t2; t2=t;}
inline void Push(rec now){
	heap[++cnt]=now;
	rr int x=cnt;
	while (x>1){
		if (heap[x]<heap[x>>1])
		    Swap(heap[x>>1],heap[x]),x>>=1;
		else return;
	}
}
inline void Pop(){
	heap[1]=heap[cnt--];
	rr int x=1;
	while ((x<<1)<=cnt){
		rr int y=x<<1;
		if (y<cnt&&heap[y+1]<heap[y]) ++y;
		if (heap[y]<heap[x]) Swap(heap[y],heap[x]),x=y;
	    else return;
	}
}
inline void dfs(int x,int fa){
	for (rr int i=as[x];i;i=e[i].next)
	if (e[i].y!=fa){
		dis[e[i].y]=e[i].w-dis[x],
		dep[e[i].y]=dep[x]+1,dfs(e[i].y,x);
	}
}
signed main(){
	n=iut(),m=iut();
	for (rr int i=1;i<n;++i){
		rr int x=iut(),y=iut(),w=iut();
		e[++k]=(node){y,w,as[x]},as[x]=k;
		e[++k]=(node){x,w,as[y]},as[y]=k;
	}
	dfs(1,0);
	for (rr int i=1;i<=n;++i)
	if (dep[i]&1) odd[++n1]=dis[i];
	    else even[++n2]=dis[i];
	if (n1<m/n2) return !printf("Stupid Mike");
	sort(odd+1,odd+1+n1),sort(even+1,even+1+n2);
	for (rr int i=1;i<=n1;++i) Push((rec){i,1,odd[i]+even[1]});
	for (rr int i=1;i<m;++i){
		rr rec Ans=heap[1]; Pop();
		if (Ans.rk2<n2) Push((rec){Ans.rk1,Ans.rk2+1,odd[Ans.rk1]+even[Ans.rk2+1]});
	}
	return !printf("%lld",heap[1].w);
} 
posted @ 2020-08-11 16:13  lemondinosaur  阅读(78)  评论(0编辑  收藏  举报