「BZOJ2152」聪聪可可
相当于求边权和为3的倍数的路径条数
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=20010,oo=INT_MAX; 4 int n,ans; 5 int tot,root,f[N],siz[N],dep_cnt[5]; 6 bool vis[N]; 7 int gcd(int a,int b){return b?gcd(b,a%b):a;} 8 struct Edge{ 9 int to,len; 10 Edge(int _to=0,int _len=0):to(_to),len(_len){} 11 }edge[N<<1]; 12 int edge_tot; 13 vector<int>point[N]; 14 void add_edge(int f,int t,int l){ 15 edge[edge_tot]=Edge(t,l); 16 point[f].push_back(edge_tot++); 17 return; 18 } 19 void getroot(int k,int fa){ 20 f[k]=0,siz[k]=1; 21 for(int i=0;i<point[k].size();i++){ 22 Edge& e=edge[point[k][i]]; 23 if(e.to==fa||vis[e.to]) continue; 24 getroot(e.to,k); 25 siz[k]+=siz[e.to]; 26 f[k]=max(f[k],siz[e.to]); 27 } 28 f[k]=max(f[k],tot-siz[k]); 29 if(f[root]>f[k]) root=k; 30 return; 31 } 32 void dfs(int k,int fa,int d){ 33 dep_cnt[d]++; 34 for(int i=0;i<point[k].size();i++){ 35 Edge& e=edge[point[k][i]]; 36 if(e.to==fa||vis[e.to]) continue; 37 dfs(e.to,k,(d+e.len)%3); 38 } 39 return; 40 } 41 int calc(int k,int d){ 42 memset(dep_cnt,0,sizeof(dep_cnt));dfs(k,0,d); 43 return dep_cnt[0]*(dep_cnt[0]-1)+2*dep_cnt[1]*dep_cnt[2]; 44 } 45 void work(int k){ 46 vis[k]=1; 47 ans+=calc(k,0); 48 for(int i=0;i<point[k].size();i++){ 49 Edge& e=edge[point[k][i]]; 50 if(vis[e.to]) continue; 51 ans-=calc(e.to,e.len); 52 root=0,tot=siz[e.to]; 53 getroot(e.to,0); 54 work(root); 55 } 56 return; 57 } 58 int main(){ 59 int t1,t2,t3; 60 f[0]=oo; 61 scanf("%d",&n); 62 for(int i=1;i<n;i++){ 63 scanf("%d%d%d",&t1,&t2,&t3); 64 add_edge(t1,t2,t3%3); 65 add_edge(t2,t1,t3%3); 66 } 67 root=0,tot=n; 68 getroot(1,0); 69 work(root); 70 ans+=n; 71 int ans2=n*n,g=gcd(ans,ans2); 72 printf("%d/%d",ans/g,ans2/g); 73 return 0; 74 }