BZOJ 3743: [Coci2015]Kamp 树形dp

3743: [Coci2015]Kamp

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 540  Solved: 254
[Submit][Status][Discuss]

Description

一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的。
有K个人(分布在K个不同的点)要集中到一个点举行聚会。
聚会结束后需要一辆车从举行聚会的这点出发,把这K个人分别送回去。
请你回答,对于i=1~n,如果在第i个点举行聚会,司机最少需要多少时间把K个人都送回家。

Input

第一行两个数,n,K。
接下来n-1行,每行三个数,x,y,z表示x到y之间有一条需要花费z时间的边。
接下来K行,每行一个数,表示K个人的分布。

Output

输出n个数,第i行的数表示:如果在第i个点举行聚会,司机需要的最少时间。

Sample Input

7 2
1 2 4
1 3 1
2 5 1
2 4 2
4 7 3
4 6 2
3
7

Sample Output

11
15
10
13
16
15
10

HINT

【数据规模】
K <= N <= 500000
1 <= x,y <= N, 1 <= z <= 1000000


挺显然的树形dp

f[i][0]表示以i为根的子树走完之后回来 f[i][1]表示不回来

f[i][1]=sigma(f[j][1]+2*val(边权))

f[i][0]=f[i][1]-max(f[j][1]-f[j][0]+val)

之后我懒的dp转移 直接用堆维护集合了 多了个log 就卡了卡常

考试时开心被卡

bzoj开心AC


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;

typedef long long ll;

#define fastcall __attribute__((optimize("-O3")))
#define IL __inline__ __attribute__((always_inline))

fastcall IL int read()
{
	int x=0,c=0;
	while(c<'0'||c>'9')c=getchar();
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
fastcall void print(ll x)
{if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=500100;

int last[N],ecnt;
struct EDGE{int to,nt,val;}e[N<<1];
fastcall IL void add(int u,int v,int val)
{e[++ecnt]=(EDGE){v,last[u],val};last[u]=ecnt;}

struct Que
{
	priority_queue<ll>A,B;
	
	fastcall IL void push(ll x){A.push(x);}
	fastcall IL void pop(ll x){B.push(x);}
	
	fastcall IL ll top()
	{
		while(!B.empty()&&!A.empty()&&A.top()==B.top())
			A.pop(),B.pop();
		return A.empty() ? 0 : A.top();
	}
	
}q[N];

int fa[N],size[N];
ll f[N][2];

fastcall void dfs(int u)
{
	for(int i=last[u],v,val;i;i=e[i].nt)
		if((v=e[i].to)!=fa[u])
		{
			fa[v]=u;
			dfs(v);
			if(size[v])
			{
				val=e[i].val;
				f[u][1]+=f[v][1]+(val<<1);
				q[u].push(f[v][1]-f[v][0]+val);
				size[u]+=size[v];
			}
		}
	f[u][0]=f[u][1]-q[u].top();
}

ll ans[N];

fastcall void solve(int u)
{
	ans[u]=f[u][0];
	for(int i=last[u],v,val,tmp[2];i;i=e[i].nt)
		if((v=e[i].to)!=fa[u])
		{
			val=e[i].val;
			if(size[v])
			{
				f[u][1]-=f[v][1]+(val<<1);
				q[u].pop(f[v][1]-f[v][0]+val);
				f[u][0]=f[u][1]-q[u].top();
			}
			tmp[0]=size[u];tmp[1]=size[v];
			size[u]-=size[v];
			size[v]+=size[u];
			if(size[u])
			{
				f[v][1]+=f[u][1]+(val<<1);
				q[v].push(f[u][1]-f[u][0]+val);
				f[v][0]=f[v][1]-q[v].top();
			}
			
			solve(v);
			
			if(size[u])
			{
				f[v][1]-=f[u][1]+(val<<1);
				q[v].pop(f[u][1]-f[u][0]+val);
				f[v][0]=f[v][1]-q[v].top();
			}
			size[u]=tmp[0];size[v]=tmp[1];
			if(size[v])
			{
				f[u][1]+=f[v][1]+(val<<1);
				q[u].push(f[v][1]-f[v][0]+val);
				f[u][0]=f[u][1]-q[u].top();
			}
		}
}

fastcall int main()
{
	int n=read(),K=read();
	register int i,u,v,val;
	for(i=1;i<n;++i)
	{
		u=read();v=read();val=read();
		add(u,v,val);add(v,u,val);
	}
	for(i=1;i<=K;++i)size[read()]=1;
	dfs(1);
	solve(1);
	for(i=1;i<=n;++i)
		print(ans[i]),puts("");
	return 0;
}
/*
7 2
1 2 4
1 3 1
2 5 1
2 4 2
4 7 3
4 6 2
3
7

11
15
10
13
16
15
10
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值