题:https://www.lydsy.com/JudgeOnline/problem.php?id=2152。
思路:要求求距离为3的倍数的所有有序点对,可以点分治,对于每一个子树找到重心计算到他距离为0,1,2的点的个数,统计求和
#include<bits/stdc++.h>
#define read(x) scanf("%d",&x)
using namespace std;
const int inf=1e9;
const int maxn=2e5;
typedef long long LL;
struct edge{
int to;
int next;
int v;
}e[maxn*2];
int n,cnt,ans,root,sum;
int last[maxn],son[maxn],f[maxn],d[maxn],t[5];
bool vis[maxn];
int gcd(int a,int b) {
if(b==0) return a;
else return gcd(b,a%b);
}
void addedge(int u,int v,int w) {
e[++cnt].to=v;
e[cnt].next=last[u];
e[cnt].v=w;
last[u]=cnt;
e[++cnt].to=u;
e[cnt].next=last[v];
e[cnt].v=w;
last[v]=cnt;
}
void getroot(int x,int fa) {
son[x]=1;
f[x]=0;
for(int i=last[x];i;i=e[i].next) {
if(!vis[e[i].to] && e[i].to != fa) {
getroot(e[i].to,x);
son[x]+=son[e[i].to];
f[x]=max(f[x],son[e[i].to]);
}
}
f[x]=max(f[x],sum-son[x]);
if(f[x]<f[root]) root=x;
}
void getdeep(int x,int fa) {
t[d[x]]++;
for(int i=last[x];i;i=e[i].next) {
if(!vis[e[i].to] && e[i].to != fa) {
d[e[i].to]=(d[x]+e[i].v)%3;
getdeep(e[i].to,x);
}
}
}
int cal(int x,int now) {
t[0]=t[1]=t[2]=0;
d[x]=now;
getdeep(x,0);
return t[1]*t[2]*2+t[0]*t[0];
}
void work(int x) {
ans+=cal(x,0);
vis[x]=1;
for(int i=last[x];i;i=e[i].next) {
if(!vis[e[i].to]) {
ans-=cal(e[i].to,e[i].v);
root=0;
sum=son[e[i].to];
getroot(e[i].to,0);
work(root);
}
}
}
int main() {
read(n);
int u,v,w;
for(int i=1;i<n;i++) {
read(u);
read(v);
read(w);
w=w%3;
addedge(u,v,w);
}
f[0]=sum=n;
getroot(1,0);
work(root);
int t=gcd(ans,n*n);
printf("%d/%d\n",ans/t,n*n/t);
return 0;
}