点分治模板题
注意calc计算的时候 注意一个端点经过x的链也是要统计的!!
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// const int N=2e6+10; int n,m,cnt,d[N],head[N],pos,siz[N],sum,x,y,z,ans,vis[N],t[5],root,maxson[N]; struct Edge{int to,nex,v;}edge[N<<1]; void add(int a,int b,int c){edge[++pos]=(Edge){b,head[a],c};head[a]=pos;} void getroot(int x,int fa) { siz[x]=1;maxson[x]=0; for(int i=head[x];i;i=edge[i].nex) { int v=edge[i].to; if(vis[v]||v==fa)continue; getroot(v,x);siz[x]+=siz[v]; maxson[x]=max(maxson[x],siz[v]); } maxson[x]=max(maxson[x],sum-siz[x]); if(maxson[x]<maxson[root])root=x; } void getdis(int x,int fa) { t[d[x]]++; for(int i=head[x];i;i=edge[i].nex) { int v=edge[i].to; if(vis[v]||v==fa)continue; d[v]=(d[x]+edge[i].v)%3; getdis(v,x); } } int calc(int x,int v) { t[0]=t[1]=t[2]=0; d[x]=v%3; getdis(x,0); return t[0]*t[0]+t[1]*t[2]*2; } void solve(int x) { see(x); vis[x]=1;ans+=calc(x,0); for(int i=head[x];i;i=edge[i].nex) { int v=edge[i].to; if(vis[v])continue; ans-=calc(v,edge[i].v); root=0;sum=siz[v]; getroot(v,x); solve(root); } } int main() { scanf("%d",&n); rep(i,1,n-1) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z); sum=maxson[0]=n;//一定要初始化 为了每次求根的时候的初始化 root=0; getroot(1,0); solve(root); printf("%d/%d ",ans/__gcd(n*n,ans),n*n/__gcd(n*n,ans)); return 0; }