2020 CCPC 威海站 C Rencontre (换根DP)

Description

Located at the easternmost tip of Shandon Peninsula, Weihai is one of the most famous tourist destinations all over China. There are beautiful hills, seas, bays, springs, islands, and beautiful beaches in Weihai. It is also a coastal city abundant in seafood, including prawn, sea cucumber, abalone, shellfish, and algae.

Attracted by the distinctive scenery and pleasant environment, three theoretical computer scientists plan to have a trip to Weihai. However, they cannot reach a consensus on accommodation, since some people prefer some hotels while other people like others. They decide to stay in separate hotels at night and meet in one hotel the next day. The hotel they meet may not necessarily be one of the hotels they stay in.

There are some roads connecting the hotels in Weihai. The roads are specially designed such that there is a unique path between every pair of hotels. Every theoretical computer scientist has prepared a list of candidate hotels before their trip starts. When they arrive in Weihai, each of them will uniformly and independently choose one hotel from the candidate hotel list. Also, they will meet in a hotel such that the total length of their routes is minimized. As a member of the theoretical computer science group, can you tell the expected total length of their routes?

Input Specification:

The first line of the input contains a single integer n ( 1 ≤ n ≤ 200000 ) n (1≤n≤200000) n(1n200000), denoting the number of hotels in Weihai. Then follow n − 1 n−1 n1 lines, describing the roads connecting the hotels. Each of the n − 1 n−1 n1 lines contains three integers u , v , w ( 1 ≤ u , v ≤ n , u ≠ v , 1 ≤ w ≤ 1000 ) u,v,w (1≤u,v≤n,u≠v,1≤w≤1000) u,v,w(1u,vn,u=v,1w1000), denoting a road of length w w w connecting the hotels numbered u u u and v v v. It is guaranteed that there is a unique path between every pair of hotels.

The last three lines of the input specify the candidate hotel lists, one for each theoretical computer scientist. Each line begins with a single integer m ( 1 ≤ m ≤ n ) m (1≤m≤n) m(1mn) and m m m distinct integers a 1 , a 2 , ⋯ , a m ( 1 ≤ a i ≤ n ) a1,a2,⋯,am (1≤ai≤n) a1,a2,,am(1ain), meaning that the candidate hotel list contains the hotels numbered a 1 , a 2 , ⋯ , a m a1,a2,⋯,am a1,a2,,am.

Output Specification:

Print the expected total length of their routes within an absolute or relative error of no more than 1 0 − 6 10^{-6} 106.

Sample Input 1:

3
1 2 1
2 3 2
1 1
1 2
1 3

Sample Output 1:

3

Sample Input 2:

5
1 2 3
1 3 5
2 4 7
2 5 11
3 2 4 5
4 1 2 3 5
2 1 3

Sample Output 2:

13.958333333333

分析

这题比赛的时候只在最后十几分钟时瞟了一眼,赛后再看还是不会做。看别人题解把这题转化成换根DP问题的那一刻才感觉感觉茅塞顿开。

给定一棵带权树,以及三个标记点列表 L 1 , L 2 , L 3 L1,L2,L3 L1,L2,L3,求 m i n ∑ { d i s ( u 1 i , v ) + d i s ( u 2 i , v ) + d i s ( u 3 i , v ) } , min\sum{\{dis(u_{1i},v)+dis(u_{2i},v)+dis(u_{3i},v)\}}, min{dis(u1i,v)+dis(u2i,v)+dis(u3i,v)},其中 u 1 i ∈ L 1 , u 2 i ∈ L 2 , u 3 i ∈ L 3 , v u_{1i} \in L1, u_{2i} \in L2,u_{3i} \in L3, v u1iL1,u2iL2,u3iL3,v为树上任意点。

思考一下可以把上式转化为求 m i n ∑ { 1 2 ( d i s ( u 1 i , u 2 i ) + d i s ( u 2 i , u 3 i ) + d i s ( u 3 i , u 1 i ) ) } min\sum{\{\frac12(dis(u_{1i},u_{2i})+dis(u_{2i},u_{3i})+dis(u_{3i},u_{1i}))\}} min{21(dis(u1i,u2i)+dis(u2i,u3i)+dis(u3i,u1i))}

如果对于每一组 d i s ( u 1 i , u 2 i ) dis(u_{1i},u_{2i}) dis(u1i,u2i)都求一次最短路那就铁炸了,因为数据范围也不能用floyd,我会的各种图论算法都搞不了。

这时候就得来点灵感了,考虑将三个标记点列表分成三张图。分别对每张图 L k Lk Lk运用换根DP的思想求出图上任一点 x x x到其他标记点的距离之和 d p [ L k ] [ x ] dp[Lk][x] dp[Lk][x],此时 d i s ( u 1 i , u 2 i ) dis(u_{1i},u_{2i}) dis(u1i,u2i)等于 ∑ d p [ L 2 ] [ u 1 i ] , u 1 i ∈ L 1 \sum dp[L2][u_{1i}],u_{1i} \in L1 dp[L2][u1i],u1iL1。对于其他项做同样处理然后最后做个除法消去重复计算的边即可得出最终结果。

两个小坑:

  • 部分地方会炸long long,需要及时进行除法运算避免溢出。
  • 这题的递归比较深,dfs里参数太多可能爆栈。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN=200000+5;
typedef long long ll;
int child[MAXN];
struct node{
	int to;
	int w;
};
vector<node> g[MAXN];

ll *t_dp;
char *t_has;
int N;

void prev_dfs(int u,int fa){
	for(node x:g[u]){
		int v=x.to;
		if(v==fa) continue;
		prev_dfs(v,u);
		t_dp[u]+=t_dp[v]+(1LL*child[v]+t_has[v])*x.w;
		child[u]+=(child[v]+t_has[v]);
	}
}

void next_dfs(int u,int fa,int fa_w){
	if(u!=fa) t_dp[u]=t_dp[fa]+(1LL*N-2*child[u]-2*t_has[u])*fa_w;
	for(node x:g[u]){
		int v=x.to;
		if(v==fa) continue;
		next_dfs(v,u,x.w);
	}
}

ll dp[3][MAXN];
char has[3][MAXN];
int cnt[3];

void init(int i){
	memset(dp,0,sizeof(dp));
	memset(has,0,sizeof(has));
}

int main(){
	int n;
	scanf("%d",&n);
	for(int i=0;i<n-1;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		g[u].push_back(node{v,w});
		g[v].push_back(node{u,w});
	}
	for(int k=0;k<3;k++){
		memset(child,0,sizeof(child));
		scanf("%d",&cnt[k]);
		for(int i=0;i<cnt[k];i++){
			int x;
			scanf("%d",&x);
			has[k][x]=1;
		}
		t_dp=dp[k];
		t_has=has[k];
		N=cnt[k];

		prev_dfs(1,1);
		next_dfs(1,1,0);
	}
	long double ans=0;
	for(int k=0;k<3;k++){
		for(int j=k+1;j<3;j++){
			long double one=1.0;
			for(int i=1;i<MAXN;i++){
				if(has[k][i]){
					ans+=one*dp[j][i]/(one*cnt[k]*cnt[j]);
				}
			}
		}
	}
	printf("%.10Lf",ans/2.0);
	return 0;
	
}

参考资料:

换根dp小结_a_forever_dream的博客-CSDN博客

2020CCPC(威海) - Rencontre(树形dp)_Falcon的博客-CSDN博客

2020ccpc威海 Rencontre - Lesning - 博客园

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值