「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 }
原文地址:https://www.cnblogs.com/mycups/p/8528042.html