题解 P6419 【[COCI2014-2015#1] Kamp】

题解 - P 6419 \mathrm{P6419}

题目意思

S o l \mathrm{Sol}

  • 因为要求每个点为根的答案,显然会想到换根 D P DP (虽然不一定

  • 我们首先先申明几个变量:

    • f u f_u 表示把 u u 子树内的任务做完并且回到 u u 点的花费

    • g u g_u 表示 u u 子树外的花费

    • d i s u , 0 / 1 dis_{u,0/1} 表示 u u 子树内的最长链/次长链

    • u p u up_u 表示 u u 子树外的最长链

  • 那么对于每个点的贡献 a n s i = f i + g i max ( u p i , d i s i , 0 ) ans_i=f_i+g_i-\max(up_i,dis_{i,0}) 。这个如何理解:就是子树内的要加子树外的也要加,我们可以选择一个位置 v v 为结束点,此刻我们就不用回溯至子树根节点了。按照贪心我们选择对答案贡献最大的点。

  • f u f_u 很好求,即 f u = v u f v + ( 2 × w u , v ) f_u=\sum_{v∈u}f_v+(2\times w_{u,v}) 。这个就不多讲了。

  • g v g_v 稍微想想可以理解即 g v = g u + ( f u f v ) g_v=g_u+(f_u-f_v) 这个如何理解:就是这个 g v g_v 包含了 u u 外的子树(这个贡献即为 g u g_u )以及同属于 u u 子树但不为 v v 的另外子树(这个贡献即为 f u f v f_u-f_v

  • u p v up_v 分两种情况:一种为其父节点 u u 的最长链上的点,以及不为最长链上的点。这个也很好转移

  • d i s u , 0 / 1 dis_{u,0/1} 在预处理中就可以处理好。

  • 以及要考虑一种情况即 v u v∈u 没有关键点,那么 g v g_v 要加上 2 × w u , v 2\times w_{u,v}

  • 时间复杂度 O ( n ) O(n)

C o d e \mathrm{Code}

#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,b,a) for ( int i=(b);i>=(a);i-- )
#define GO(i,x) for ( int i=head[x];i;i=e[i].nex )
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define YES return puts("YES"),0
#define NO return puts("NO"),0
#define GG return puts("-1"),0
#define pb push_back
#define int long long
using namespace std;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

const int mod=1e9+7;
const int mo=998244353;
const int N=5e5+5;

int n,m,cnt,head[N],f[N],g[N];
int dis[N][2],a[N],up[N],siz[N],ans;

struct Node
{
	int nex,to,w;
};
Node e[N<<1];

inline void jia(int u,int v,int w)
{
	e[++cnt].nex=head[u];
	head[u]=cnt;
	e[cnt].to=v;
	e[cnt].w=w;
}

inline void dfs(int u,int fa)
{
	siz[u]=a[u];
	GO(i,u)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
		if(siz[v])
		{
			f[u]+=(f[v]+2*e[i].w);
			if(dis[u][0]<dis[v][0]+e[i].w) 
				dis[u][1]=dis[u][0],dis[u][0]=dis[v][0]+e[i].w;
			else if(dis[u][1]<dis[v][0]+e[i].w) dis[u][1]=dis[v][0]+e[i].w;
		}
	}
}

inline void dp(int u,int fa)
{
	GO(i,u)
	{
		int v=e[i].to;
		if(v==fa) continue;
		if(m-siz[v])
		{
			g[v]=g[u]+(f[u]-f[v]);
			if(!siz[v]) g[v]+=2*e[i].w; 
			if(dis[v][0]+e[i].w==dis[u][0]) 
				up[v]=max(up[u],dis[u][1])+e[i].w;
			else up[v]=max(up[u],dis[u][0])+e[i].w;
		}
		dp(v,u);
	}
}

signed main()
{
	n=read();m=read();
	For(i,1,n-1)
	{
		int x,y,w;
		x=read(),y=read(),w=read();
		jia(x,y,w);
		jia(y,x,w);
	}
	For(i,1,m) a[read()]++;
	dfs(1,0);
	dp(1,0);
	For(i,1,n) printf("%lld\n",f[i]+g[i]-max(up[i],dis[i][0]));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wangyiyang2/article/details/106960723
今日推荐