点分治
简单的点分治应用,即统计距离%3=0的点对。
设 t[0],t[1],t[2] 分别为到根节点距离为0、距离为1、距离为2(%3意义下)的点数,则答案为 2t[1]t[2]+t[0]2
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 20000
using namespace std;
struct edge{
int next,to,dis;
}ed[MAXN*2+5];
int n,k,rt,t,p,ans;
int h[MAXN+5],sum[MAXN+5],dep[3],dis[MAXN+5],ma[MAXN+5];
bool f[MAXN+5];
inline char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; return *l++;
}
inline int _read(){
int num=0; char ch=readc();
while (ch<'0'||ch>'9') ch=readc();
while (ch>='0'&&ch<='9') { num=num*10+ch-48; ch=readc(); }
return num;
}
void addedge(int x,int y,int z){
ed[++k].next=h[x]; ed[k].to=y; ed[k].dis=z; h[x]=k;
}
void dfsrt(int x,int fa){
sum[x]=1; ma[x]=0;
for (int i=h[x];i;i=ed[i].next)
if (ed[i].to!=fa&&!f[ed[i].to]){
int v=ed[i].to; dfsrt(v,x);
sum[x]+=sum[v]; ma[x]=max(ma[x],sum[v]);
}
ma[x]=max(ma[x],t-sum[x]);
if (ma[x]<ma[rt]) rt=x;
}
void dfsdep(int x,int fa){
dep[dis[x]%3]++;
for (int i=h[x];i;i=ed[i].next)
if (ed[i].to!=fa&&!f[ed[i].to]){
dis[ed[i].to]=(dis[x]+ed[i].dis)%3;
dfsdep(ed[i].to,x);
}
}
int dfssum(int x,int v){
dis[x]=v%3; dep[0]=dep[1]=dep[2]=0; dfsdep(x,0);
return dep[1]*dep[2]*2+dep[0]*dep[0];
}
void dfsans(int x){
f[x]=true; ans+=dfssum(x,0);
for (int i=h[x];i;i=ed[i].next)
if (!f[ed[i].to]){
int v=ed[i].to;
ans-=dfssum(v,ed[i].dis);
rt=0; t=sum[v];
dfsrt(v,0); dfsans(rt);
}
}
int gcd(int a,int b){
if (b==0) return a;
return gcd(b,a%b);
}
int main(){
n=_read();
for (int i=1;i<n;i++){
int u=_read(),v=_read(),d=_read()%3;
addedge(u,v,d); addedge(v,u,d);
}
t=n; ma[0]=0x7fffffff;
dfsrt(1,0); dfsans(rt);
int r=gcd(ans,n*n);
printf("%d/%d",ans/r,n*n/r);
return 0;
}