题目大意:给定一棵树,每条边上有边权,求距离为3的倍数的有序点对
题解:考虑路径经过重心的情况,记录到根的距离%3=0,1,2的点数
ans=sum[0]2+2∗sum[1]∗sum[2],乘法原理
我的收获:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int M=20005;
#define INF 0x3f3f3f3f
int n,t,head[M];
int temp,root,ans;
int sz[M],f[M],cnt[3],d[M];
bool vis[M];
struct edge{int to,val,nex;}e[M<<1];
void add(int u,int v,int w){e[t]=(edge){v,w,head[u]};head[u]=t++;}
void dfsroot(int x,int fa){
sz[x]=1;f[x]=0;
for(int i=head[x];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v!=fa&&!vis[v]) dfsroot(v,x),sz[x]+=sz[v],f[x]=max(f[x],sz[v]);
}
f[x]=max(f[x],temp-sz[x]);
if(f[x]<f[root]) root=x;
}
void getdep(int x,int fa){
cnt[d[x]]++;
for(int i=head[x];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v!=fa&&!vis[v]) d[v]=(d[x]+e[i].val)%3,getdep(v,x);
}
}
int calc(int x,int now)
{
cnt[0]=cnt[1]=cnt[2]=0;
d[x]=now,getdep(x,0);
return cnt[0]*cnt[0]+cnt[1]*cnt[2]*2;
}
void solve(int x)
{
ans+=calc(x,0);vis[x]=1;
for(int i=head[x];i!=-1;i=e[i].nex)
if(!vis[e[i].to])
{
ans-=calc(e[i].to,e[i].val);
root=0;temp=sz[e[i].to];
dfsroot(e[i].to,0);solve(root);
}
}
void divide()
{
f[0]=INF,temp=n;
dfsroot(1,0),solve(root);
}
void work()
{
divide();
int t=__gcd(ans,n*n);
printf("%d/%d",ans/t,n*n/t);
}
void init()
{
cin>>n;
t=0;memset(head,-1,sizeof(head));
int x,y,z;
for(int i=1;i<n;i++) scanf("%d%d%d",&x,&y,&z),add(x,y,z%3),add(y,x,z%3);
}
int main()
{
init();
work();
return 0;
}