http://www.lydsy.com/JudgeOnline/problem.php?id=2152
还是点分治棵题
分治写法一样
只是维护的信息是路径长度mod 3的余数
#include<cstdio> #include<algorithm> #define FOR(i,s,t) for(register int i=s;i<=t;++i) #define ROF(i,s,t) for(register int i=s;i>=t;--i) #define VIS(now) for(register int e=las[now];e;e=nxt[e]) using std::sort; typedef long long ll; ll ans,_ans,g; int n,k,tot; const int N=100011; int sz[N],vis[N]; int dis[N],t[3]; int las[N],nxt[N<<1],w[N<<1],f[N],to[N<<1],son[N<<1]; inline int max(int a,int b){ return a>b?a:b; } inline void add(int x,int y,int z){ nxt[++tot]=las[x];las[x]=tot;w[tot]=z;to[tot]=y; } inline int find(int rt){ static int qn,que[N]; que[qn=1]=rt,f[rt]=0; int v,u,mx=n,G=0; FOR(ql,1,qn){ sz[u=que[ql]]=1,son[u]=0; VIS(u) if(!vis[v=to[e]]&&v!=f[u]){ f[v]=u; que[++qn]=v; } } ROF(ql,qn,1){ u=que[ql],v=f[u]; if(qn-sz[u]>son[u])son[u]=qn-sz[u]; if(son[u]<mx)G=u,mx=son[u]; if(!v)break; sz[v]+=sz[u]; if(sz[u]>son[v])son[v]=sz[u]; } return G; } inline ll calc(int rt,int L){ static int qn,que[N]; int u,v; que[qn=1]=rt,dis[rt]=L,f[rt]=0; t[0]=t[1]=t[2]=0; FOR(ql,1,qn){ ++t[dis[u=que[ql]]%3]; VIS(u) if(!vis[v=to[e]]&&v!=f[u]) f[v]=u,dis[v]=dis[u]+w[e],que[++qn]=v; } return 1ll*t[0]*(t[0]-1)/2+1ll*t[1]*t[2]; } inline void dfs(int x){ int G=find(x); vis[G]=1; ans+=calc(G,0); VIS(G) if(!vis[to[e]]) ans-=calc(to[e],w[e]); VIS(G) if(!vis[to[e]]) dfs(to[e]); } int x,y,z; inline ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } int main(){ scanf("%d",&n); FOR(i,2,n){ scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } dfs(1); ans=1ll*(ans<<1)+n; _ans=1ll*n*n; g=gcd(ans,_ans); printf("%lld/%lld ",ans/g,_ans/g); return 0; }