1. 程式人生 > >P2634 [國家集訓隊]聰聰可可

P2634 [國家集訓隊]聰聰可可

using ons 直接 sof 國家集訓隊 國家 clas const max

題意:求樹上路徑權值和為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 [國家集訓隊]聰聰可可