基础点分治。
点分治的模板基础上改一下即可。
询问树上长度模数是3的路径
//询问有多少路径的长度加起来是3的倍数
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n;
vector<pair<int,int> > g[maxn];
int vis[maxn],rt,sz[maxn],Tsz,wt[maxn],arr[maxn],cnt;
long long ans;
void getRoot (int u,int pre) {
sz[u]=1;
wt[u]=0;
for (pair<int,int> it:g[u]) {
int v=it.first;
if (!vis[v]&&v!=pre) {
getRoot(v,u);
sz[u]+=sz[v];
wt[u]=max(wt[u],sz[v]);
}
}
wt[u]=max(wt[u],Tsz-sz[u]);
if (wt[rt]>wt[u]) rt=u;
}
void dfs1 (int u,int dep,int pre) {
arr[++cnt]=dep;
for (pair<int,int> it:g[u]) {
int v=it.first;
if (v!=pre&&!vis[v]) dfs1(v,dep+it.second,u);
}
}
int cc[4];
long long calc (int u,int dep) {
cnt=0;
dfs1(u,dep,0);
memset(cc,0,sizeof(cc));
for (int i=1;i<=cnt;i++) cc[arr[i]%3]++;
long long ans=1ll*cc[0]*cc[0]+1ll*cc[1]*cc[2]+1ll*cc[1]*cc[2];
return ans;
}
void dfs (int u) {
ans+=calc(u,0);
vis[u]=1;
for (pair<int,int> it:g[u]) {
int v=it.first;
if (!vis[v]) {
ans-=calc(v,it.second);//容斥减掉非法路径
rt=0;
Tsz=sz[v];
getRoot(v,0);
dfs(rt);
}
}
}
int main () {
scanf("%d",&n);
for (int i=1;i<n;i++) {
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
g[u].push_back(make_pair(v,w));
g[v].push_back(make_pair(u,w));
}
wt[rt=0]=1e9;
Tsz=n;
getRoot(1,0);
dfs(rt);
long long fm=1ll*n*n;
long long gg=__gcd(ans,fm);
ans/=gg;
fm/=gg;
printf("%lld/%lld",ans,fm);
}