标签:work continue AC roo using 总结 names turn 直接
题意:求树上路径权值和为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; }
标签:work continue AC roo using 总结 names turn 直接
原文地址:https://www.cnblogs.com/oi-forever/p/9129429.html