2020 CCPC-Wannafly Winter Camp Day3 G-火山哥周游世界

令len[x]表示特殊点(即要去的地方)到u的距离。
那么从u出发 走完所有特殊点所需要的代价是 2[sigma(len[x])]-max(len[x])
令dp[u]表示从小到上,特殊点到u的距离和。我们如果从1出发,sigma(len[x])就可以通过一次dfs求得。我们令sum表示距离和。
当1的子节点为根节点的时候,假设为u。当u的子树有特殊点,sum-=2
wi。当u除了子树外,还有特殊点,sum+=2*wi。
接着我们计算max(len[x])。这个就是树上任意一点,其他点到这个点的最长距离。我们利用记录最大值和次大值dp来解决这个问题。
令maxx[u]表示u的子树中,到u的最长距离。maxx2[u]表示次长距离。令nxt[u]表示u的最长距离链上,u的直接子节点。
同样,因为特殊点可能在u的子树之外,所以令famax[u]表示,u向上走的最大距离。
对于u的任意一个子节点v,我们可以得到一个dp表达式:
if(v==nxt[u])famax[v]=max(famax[u]+wi,maxx2[u]+wi)
else famax[v]=max(famax[u]+wi,maxx[u]+wi)。
故我们求得 1为根节点后,max和sigma值可以根据1节点的答案dp出来。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 5e5 + 10;
ll dp[N];
ll ffmax[N], ssmax[N], nxt[N], anx[N], famax[N];
int n, k;
struct node { ll to, next, wi; }edge[N<<1];
int head[N << 1];
int cnt;
int sz[N], fa[N];
ll ans[N];
void addedge(ll u, ll v, ll w)
{
	edge[cnt].to = v;
	edge[cnt].wi = w;
	edge[cnt].next = head[u];
	head[u] = cnt++;
}
void dfs1(int u, int f)
{
	fa[u] = f;
	ll temp = 0;
	for (int i = head[u]; ~i; i = edge[i].next)
	{
		int v = edge[i].to;
		if (v == f)continue;
		dfs1(v, u);
		sz[u] += sz[v];
		if (sz[v])
		{
			dp[u] += dp[v] + 2 * edge[i].wi;
			if (ffmax[v] + edge[i].wi > temp)
			{
				temp = ffmax[v] + edge[i].wi;
				ssmax[u] = ffmax[u];
				ffmax[u] = temp;
				nxt[u] = v;
			}
			else ssmax[u] = max(ssmax[u], ffmax[v] + edge[i].wi);
		}
	}
}
void dfs2(int u)
{
	for (int i = head[u]; ~i; i = edge[i].next)
	{
		int v = edge[i].to;
		if (v == fa[u])continue;
		if (k - sz[v])
		{
			if (v == nxt[u])
			{
				famax[v] = max(famax[u], ssmax[u]) + edge[i].wi;
			}
			else
			{
				famax[v] = max(famax[u], ffmax[u]) + edge[i].wi;
			}
		}
		ans[v] = ans[u];
		if (sz[v])ans[v] -= 2 * 1ll * edge[i].wi;
		if (k - sz[v])ans[v] += 2 * 1ll * edge[i].wi;
		dfs2(v);
	}
}
int main()
{
	memset(head, -1, sizeof(head));
	n = read(), k = read();
	ll u, v, w;
	up(i, 0, n - 1) {
		u = read(), v = read(); w = read();
		addedge(u, v, w);
		addedge(v, u, w);
	}
	up(i, 0, k)
	{
		u = read();
		sz[u]++;
	}
	dfs1(1, 0);
	ans[1] = dp[1];
	dfs2(1);
	upd(i, 1, n)
	{
		printf("%lld\n", ans[i] - max(famax[i], ffmax[i]));
	}
	return 0;
}
posted @ 2020-03-06 16:28  LORDXX  阅读(143)  评论(0编辑  收藏  举报