HDU 4303 Hourai Jeweled 树形dp 所有路径点权和 dfs2次

题意:

long long ans = 0;

for(int i = 1; i <= n; i++)

for(int j = i+1; j <= n; j++)

ans += F(i,j);

F(i,j)表示i点到j点路径上所有的点权和。

若i->j路径上存在2条相邻边边权相同则 F(i,j) = 0

问:ans的值。

int乘法爆掉了我也醉了。。。

思路:

和网上的统计边方法不同,这里是用统计点出现的次数来计算

我们计算每个点i 出现的次数,则答案就是 i的次数*i的点权 => dp[i] * a[i]

而i出现的路径起点和终点有4种

1、i的子孙->i的子孙

2、i的子孙->i

3、i到 (非i的子孙( 即i的祖先节点,兄弟节点和兄弟节点的子孙

4、i的子孙->非i的子孙

所以先计算1,2的情况 ,用dp1[i]记录

3,4的情况用dp2[i]记录

则答案就是 for(int i = 1; i <= n; i++) ans += a[i] * (dp1[i]+dp2[i]);

siz[u] 表示以u为根的子树中有效的节点数,若 u -> v(col = 1) && v -> k(col=1), 则以k为根的子树都不是有效节点

(其中v是u的儿子,k是v的儿子)

mp[u][col]表示以u为根,有效节点中 用颜色为col的边相连的节点个数

#include <map>
using namespace std;
#define N 300100
struct Edge{
	int to, col, nex;
}edge[N<<1];
int head[N], edgenum;
void init(){memset(head, -1, sizeof head); edgenum = 0;}
void add(int u, int v, int col){
	Edge E = {v, col, head[u]};
	edge[edgenum] = E;
	head[u] = edgenum++;
}
typedef long long ll;
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if(c=getchar(),c==EOF) return 0;
	while(c!='-'&&(c<'0'||c>'9')) c=getchar();
	sgn=(c=='-')?-1:1;
	ret=(c=='-')?0:(c-'0');
	while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
	ret*=sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if(x>9) pt(x/10);
	putchar(x%10+'0');
}
int n, k;
ll dp1[N], dp2[N], a[N];
int siz[N];
map<int, int> mp[N], mp2[N];//mp[u][col]表示u子树下 边颜色=col 的有效的点数
void dfs1(int u, int fa){
	siz[u] = 0;    dp1[u] = 0;
	for(int i = head[u]; ~i; i = edge[i].nex) {
		int v = edge[i].to; if(v == fa)continue;
		dfs1(v, u);
		mp[u][edge[i].col] += siz[v] - mp[v][edge[i].col];
		siz[u] += siz[v] - mp[v][edge[i].col];
	}
	ll dou = 0;
	for(int i = head[u]; ~i; i = edge[i].nex) {
		int v = edge[i].to; if(v == fa)continue;
		dou += (ll)(siz[v] - mp[v][edge[i].col]) * (ll)(siz[u] - mp[u][edge[i].col]);
		dp1[u] += siz[v] - mp[v][edge[i].col];
	}
	dp1[u] += dou >> 1;
	siz[u]++;
}
void dfs2(int u, int ok, int col, int fa) {
	dp2[u] = (ll)(siz[u] - mp[u][col]) * (ll)ok;
	for(int i = head[u]; ~i; i = edge[i].nex) {
		int v = edge[i].to; if(v == fa)continue;
		if(u != fa && edge[i].col == col)
			dfs2(v, siz[u] - mp[u][edge[i].col], edge[i].col, u);
		else
			dfs2(v, ok + siz[u] - mp[u][edge[i].col], edge[i].col, u);
	}
}
void solve(){
	init();
	for(int i = 1; i <= n; i++)rd(a[i]), mp[i].clear(), mp2[i].clear();
	for(int i = 1, u, v, d; i < n; i++) {
		rd(u);rd(v);rd(d);
		add(u,v,d); add(v,u,d);
	}
	dfs1(1, 1);
	dfs2(1, 0, -1, 1);
}
int main() {
	while(rd(n)){
		solve();
		ll ans = 0;
		for(int i = 1; i <= n; i++)
			ans += a[i]*(dp1[i]+dp2[i]);
		pt( ans );putchar('\n');
	}
	return 0;
}
/*
4
1 10 100 1000
1 2 1
2 3 1
3 4 1

5
1 10 100 1000 10000
1 2 1
2 3 1
3 4 1
2 5 2

11
1 2 3 4 5 6 7 8 9 111 123
1 2 1
1 3 2
2 4 3
2 5 1
3 6 3
3 7 3
5 8 1
5 9 2
8 10 1
11 8 2

14
1 2 3 4 5 6 7 8 9 111 123 235 66 1000
1 2 1
1 3 2
2 4 3
2 5 1
3 6 3
3 7 3
5 8 1
5 9 2
8 10 1
11 8 2
12 11 2
8 13 1
8 14 2

10
1 1 1 1 1 1 1 1 1 1
1 2 1
1 7 1
1 10 2
2 3 5
2 6 4
3 4 1
3 5 8
7 8 2
7 9 1

14
1 2 5 10 20 30 70 80 100 1000 2000 5000 100000 1000000
1 2 2
1 3 1
1 4 1
2 5 2
2 8 3
3 9 3
3 6 2
4 7 1
4 10 3
3 11 3
6 12 2
13 1 2
14 3 3

*/
时间: 2024-11-05 15:59:37

HDU 4303 Hourai Jeweled 树形dp 所有路径点权和 dfs2次的相关文章

HDU 4303 Hourai Jeweled 解题报告

HDU 4303 Hourai Jeweled 解题报告 评测地址: http://acm.hdu.edu.cn/showproblem.php?pid=4303 评测地址: https://xoj.red/contests/view/1155/1 题目描述 Kaguya Houraisan was once a princess of the Lunarians, a race of people living on the Moon. She was exiled to Earth over

HDU 4303 Hourai Jeweled(树形DP)

http://acm.hdu.edu.cn/showproblem.php?pid=4303 题意:给出一棵树,树上的每一个节点都有一个权值,每条边有一个颜色,如果一条路径上相邻边的颜色都是不同的,那么它就是符合要求的.求出所有符合要求的路径上的节点的权值和. 思路:num[u]表示u节点下有几条符合要求的子树路径,sum[u]表示u为起点(或者终点也可以)往子树方向符合要求的路径权值和. 如图,u的父节点颜色为1,u->v的边颜色为2,那么此时u可以和v相连,num[v]就是v保留的路径数,这

【树形DP】HDU 4303 Hourai Jeweled

通道 题意:给一个树,边有颜色,点有权值.满足路径上没有两个相邻边同色的路径是好的路径,求好的路径的(路径上的点的权值和)的总和 思路: 边权排序,从任意一点开始深搜,每颗子树搜索完毕之后向上返回pair<可以延伸到该点且最后一条边与由父节点到该点的边颜色不同的gorgeous边的条数 , 所有这种边分数的总和>每次深搜完一个子节点之后,增加的过这一点的gorgeous边的总分数为:    之前深搜的所有子节点向上返回的边数之和 * 当前子节点返回的分数 +    之前深搜的所有子节点向上返回

hdu 4044 GeoDefense (树形dp+01背包)

GeoDefense Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 663    Accepted Submission(s): 267 Problem Description Tower defense is a kind of real-time strategy computer games. The goal of towe

HDU 1011 Starship Troopers(树形DP)

Starship Troopers Time Limit : 10000/5000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Submission(s) : 62   Accepted Submission(s) : 12 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description You, the leader of

hdu 1520Anniversary party(简单树形dp)

Anniversary party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4310    Accepted Submission(s): 1976 Problem Description There is going to be a party to celebrate the 80-th Anniversary of the

HDU 2196 Computer 经典树形DP

一开始看错题了,后来发现原来是在一颗带权的树上面求出距离每一个点的最长距离,做两次dfs就好,具体的看注释? #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #incl

HDU 2376 Average distance (树形dp)

Average distance Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 588    Accepted Submission(s): 213 Special Judge Problem Description Given a tree, calculate the average distance between two ve

HDU 4714:Tree2cycle 树形DP

Tree2cycle 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4714 题意: 给出一棵树,可以删边和加边将这棵树变成一个圈(没有任何分支),求最少的操作次数. 题解: 将树改造为圈可以通过现将树变成一条没有分叉的链后再加上一条边连接链的两端. 再简化一下就变成了选一条路径作为主干,再将其他所有分叉通过增删边连接到竹竿上的过程. 设DP1[i](把以 i 为根节点的子树作为主干的一部分),和DP2[i](把以 i 为根节点的子树作为分叉),