[题解] P2634 [国家集训队]聪聪可可
细节
点分治详见:
这个板子有几个细节:
-
自己到自己也算一条路径
-
处理好 \(*2\) 或者 不\(*2\) 之间的关系
-
多测不清空,亲人两行泪
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline int read(){
char c=getchar();
int x=0;bool fl=false;
while(!isdigit(c)){
if(c=='-')fl=true;
c=getchar();
}
while(isdigit(c)){
x=(x<<3)+(x<<1)+(c^48);
c=getchar();
}
return fl?-x:x;
}
const int INF = 2147483647;
const int maxn = 2e4 + 5;
int gcd(int a,int b){
if(!b)return a;
return gcd(b,a%b);
}
struct edge{
int to,nxt,w;
}e[maxn<<1];
int head[maxn],cnt=0;
inline void link(int u,int v,int w){
e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;e[cnt].w=w;
}
int mx[maxn],sz[maxn],S,rt;
bool vis[maxn];
void find_rt(int u,int fa){
sz[u]=1;mx[u]=0;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(vis[v] || v==fa)continue;
find_rt(v,u);
sz[u]+=sz[v];
mx[u]=max(mx[u],sz[v]);
}
mx[u]=max(mx[u],S-sz[u]);
if(mx[rt]>mx[u])rt=u;
}
int dis[maxn],t[5],now[5];
int dfs(int u,int fa){
now[dis[u]%3]++;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(vis[v] || v==fa)continue;
dis[v]=(dis[u]+e[i].w)%3;
dfs(v,u);
}
}
int ans=0;
void calc(int u){
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(vis[v])continue;
for(int j=0;j<3;j++)now[j]=0;
dis[v]=e[i].w%3;
dfs(v,u);
ans+=t[0]*now[0]*2+t[1]*now[2]*2+t[2]*now[1]*2+now[0]*2;
for(int j=0;j<3;j++)t[j]+=now[j];
}
}
void solve(int u){
vis[u]=true;
calc(u);
for(int i=0;i<3;i++)t[i]=0;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(vis[v])continue;
S=sz[v];rt=0;mx[rt]=INF;
find_rt(v,u);
solve(rt);
}
}
int n;
int main(){
scanf("%d",&n);
for(int i=1,u,v,w;i<n;i++){
u=read();v=read();w=read();
link(u,v,w);link(v,u,w);
}
mx[rt=0]=n;
S=n;
find_rt(1,0);
solve(rt);
ans+=n;
int g=gcd(ans,n*n);
printf("%d/%d",ans/g,n*n/g);
return 0;
}