模板题
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2152
求长度为3的倍数的路径条数
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define pb push_back
#define ll long long
using namespace std;
using namespace __gnu_pbds;
const int N = 5e4+1000;
int n,k;
struct node {
int v,w,nxt;
}edge[2*N];
int tot,head[N];
void ae(int u,int v,int w) {
edge[++tot] = node{v,w,head[u]};
head[u] = tot;
}
void init(int n) {
tot = 0;
rep(i, 1, n) head[i] = -1;
}
int siz[N],Root,wt[N],Tsiz,Tnum[4],num[4];
bool vis[N];
ll ans;
void GetRoot(int u,int f) {
siz[u] = 1;
wt[u] = 0;
for(int i = head[u]; ~i ; i = edge[i].nxt) {
int v = edge[i].v;
if(v==f||vis[v]) continue;
GetRoot(v,u);
siz[u] += siz[v];
wt[u] = max(wt[u],siz[v]);
}
wt[u] = max(wt[u],Tsiz-siz[u]);
if(wt[Root]>wt[u]) Root = u;
}
void dfs(int u,int f,int dis) {
num[dis]++;
for(int i = head[u]; ~i ; i = edge[i].nxt) {
int v = edge[i].v;
int w = edge[i].w;
if(v==f||vis[v]) continue;
dfs(v,u,(dis+w)%3);
}
}
void calc(int u) {
rep(i, 0 ,2) Tnum[i] = 0;
Tnum[0] = 1; //注意,这里并没有考虑u->u这条路径
for(int i = head[u]; ~i ; i = edge[i].nxt) {
int v = edge[i].v;
int w = edge[i].w;
if(vis[v]) continue;
rep(i, 0, 2) num[i] = 0;
dfs(v,u,w%3);
rep(i, 0, 2)
ans += 1ll*num[i]*Tnum[(3-i)%3];
rep(i, 0, 2) Tnum[i] += num[i];
}
}
void divide(int u) {
calc(u);
vis[u] = 1; //删掉该点
for(int i = head[u]; ~i ; i = edge[i].nxt) {
int v = edge[i].v;
if(vis[v]) continue;
Root = 0,Tsiz = siz[v];
GetRoot(v,0);
divide(Root);
}
}
ll gcd(ll x, ll y) {
return y==0?x:gcd(y,x%y);
}
int main() {
// freopen("a.txt","r",stdin);
//ios::sync_with_stdio(0);
scanf("%d",&n);
init(n);
rep(i, 1, n-1) {
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ae(u,v,w);
ae(v,u,w);
}
rep(i, 1, n) vis[i] = 0;
wt[0] = 1e9,Tsiz = n,GetRoot(1,0),ans = 0;
divide(Root);
ll up = ans*2+n;
ll down = n*n;
ll t = gcd(up,down);
up /= t; down /= t;
printf("%lld/%lld",up, down);
return 0;
}