https://www.luogu.com.cn/problem/P2634
点分治,在calc函数中统计长度为3的倍数的路径就可以了。
在calc中我们算出来的是点对的数量,且没有顺序,也不能选择同一个点。
所以最后我们要ans=ans*2+n,选择同一个点他们之间的路径长度是0
#include<bits/stdc++.h>
using namespace std;
const int maxl=2e4+10;
int n,cnt,ans,len;
int ehead[maxl],dis[maxl],a[maxl],t[4];
struct ed
{
int to,nxt,l;
}e[maxl<<1];
bool vis[maxl];
struct centertree
{
int n,mini,ans;
int son[maxl];
inline void dfs(int u,int fa)
{
son[u]=1;int mx=0,v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(v==fa || vis[v]) continue;
dfs(v,u);
son[u]+=son[v];
mx=max(mx,son[v]);
}
mx=max(mx,n-son[u]);
if(mx<mini)
{
ans=u;
mini=mx;
}
}
inline int getcenter(int u)
{
ans=0;mini=2e9;
dfs(u,0);
return ans;
}
}tree;
inline void add(int u,int v,int l)
{
e[++cnt].to=v;e[cnt].l=l;
e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
ehead[i]=0,vis[i]=false;
int u,v,l;cnt=0;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&l);
add(u,v,l);add(v,u,l);
}
}
inline void getdis(int u,int fa)
{
a[++len]=dis[u];
int v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(v==fa || vis[v]) continue;
dis[v]=dis[u]+e[i].l;
getdis(v,u);
}
}
inline int calc(int u,int w)
{
len=0;dis[u]=w;
getdis(u,0);
for(int i=0;i<3;i++)
t[i]=0;
for(int i=1;i<=len;i++)
t[a[i]%3]++;
int ret=0;
ret+=t[1]*t[2];
ret+=t[0]*(t[0]-1)/2;
return ret;
}
inline void solv(int u)
{
vis[u]=true;
ans+=calc(u,0);
int v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(vis[v]) continue;
ans-=calc(v,e[i].l);
tree.n=tree.son[v];
int rt=tree.getcenter(v);
solv(rt);
}
}
inline void mainwork()
{
ans=0;tree.n=n;
int rt=tree.getcenter(1);
solv(rt);
}
inline void print()
{
ans=ans*2+n;
int tot=n*n;
int d=__gcd(ans,tot);
ans/=d;tot/=d;
printf("%d/%d",ans,tot);
}
int main()
{
prework();
mainwork();
print();
return 0;
}