有点模板的点分治,
设d[i](0≤i≤2)表示路径距离%3为i的数量
那么显然,方案数就为d[1]*d[2]*2+d[0]2
#include <cstdio>
#include <algorithm>
#define N 20010
using namespace std;
struct info{int to,nex,w;}e[N*2];
int n,tot,head[N],sum,f[N],sz[N],d[3],Ans,rt;
bool vis[N];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
void Link(int u,int v,int w){
e[++tot].to=v,e[tot].w=w,e[tot].nex=head[u];head[u]=tot;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
void getrt(int u,int fa){
sz[u]=1,f[u]=0;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].to;
if(v==fa||vis[v]) continue;
getrt(v,u);
f[u]=max(f[u],sz[v]);
sz[u]+=sz[v];
}
f[u]=max(f[u],sum-sz[u]);
if(f[rt]>f[u]) rt=u;
}
void getdep(int u,int fa,int ddd){
d[ddd]++;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].to;
if(v==fa||vis[v]) continue;
getdep(v,u,(ddd+e[i].w)%3);
}
}
int calc(int u,int ddd){
d[0]=d[1]=d[2]=0;
getdep(u,0,ddd%3);
return d[1]*d[2]*2+d[0]*d[0];
}
void solve(int u){
Ans+=calc(u,0);
vis[u]=1;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].to;
if(vis[v]) continue;
Ans-=calc(v,e[i].w);
sum=sz[v];
getrt(v,rt=0);
solve(rt);
}
}
int main(){
n=read();
for(int i=1;i<n;++i){
int u=read(),v=read(),w=read();
Link(u,v,w),Link(v,u,w);
}
sum=n,f[0]=1e9,getrt(1,0);
solve(rt);
int f=gcd(n*n,Ans);
printf("%d/%d\n",Ans/f,n*n/f);
return 0;
}
原文:https://www.cnblogs.com/void-f/p/9107521.html