标签: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