P2634 [国家集训队]聪聪可可

Posted oi-forever

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2634 [国家集训队]聪聪可可相关的知识,希望对你有一定的参考价值。

题意:求树上路径权值和为3的倍数的路径条数

总结:f[0],f[1],f[2]表示权值%3后为0,1,2的点数

然后直接点分统计就好了

 

#include<bits/stdc++.h>

using namespace std;
const int maxn = 200005;

int n, head[maxn], cnt = 1, tot, f[maxn], dep[maxn], d[maxn];
struct Node{
	int v, nxt, w;
} G[maxn]; int root, ans, sum, siz[maxn], vis[maxn], dp[maxn];

void ins(int u, int v, int w) {
	G[cnt] = (Node) {v, head[u], w}; head[u] = cnt++; 
}
int gcd(int a, int b) {
	return b == 0 ?a :gcd(b, a % b);
}
void get_rt(int x, int fa) {
	siz[x] = 1; f[x] = 0;
	for (int i = head[x]; i; i = G[i].nxt) {
		int v = G[i].v;
		if(vis[v] || v == fa) continue;
		get_rt(v, x);
		siz[x] += siz[v];
		f[x] = max(f[x], siz[v]);
	} f[x] = max(f[x], ans - siz[x]);
	if(f[x] < f[root]) root = x;
}
void get_dp(int x, int fa) {
	dp[dep[x] % 3]++; 
	for (int i = head[x]; i; i = G[i].nxt) {
		int v = G[i].v;
		if(vis[v] || v == fa) continue;
		dep[v]  = dep[x] + G[i].w;
		get_dp(v, x);
	}
}
void calc(int x, int w, int sig) {
	dp[0] = dp[1] = dp[2] = 0;
	dep[x] = w; tot = 0; get_dp(x, 0);
	sig == 1 ?sum += dp[0] * dp[0] + 2 * dp[1] * dp[2] :sum -= dp[0] * dp[0] + 2 * dp[1] * dp[2];
}
void work(int x) {
	vis[x] = 1; calc(x, 0, 1);
	for (int i = head[x]; i; i = G[i].nxt) {
		int v = G[i].v;
		if(vis[v]) continue;
		calc(v, G[i].w, -1);
		root = 0; ans = siz[v];
		get_rt(v, 0); work(root);
	}
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n - 1; ++i) {
		int x, y, z; scanf("%d%d%d", &x, &y, &z);
		ins(x, y, z); ins(y, x, z);
	}
	root = 0; f[0] = 0x7fffff; ans = n;
	get_rt(1, 0); work(root);
	int temp = gcd(sum, n * n);
	printf("%d/%d", sum / temp, (n * n) / temp);
	return 0;
}

 

  

 

以上是关于P2634 [国家集训队]聪聪可可的主要内容,如果未能解决你的问题,请参考以下文章

P2634 [国家集训队]聪聪可可

P2634 [国家集训队]聪聪可可

P2634 [国家集训队]聪聪可可(点分治做法)

P2634 [国家集训队]聪聪可可(树上启发式合并)

题解:luogu P2634 [国家集训队]聪聪可可

P2634 [国家集训队]聪聪可可(树形dp)