[BZOJ2152]聪聪可可(点分治)
有点模板的点分治,
设d[i](0≤i≤2)表示路径距离%3为i的数量
那么显然,方案数就为d[1]*d[2]*2+d[0]2
Code
#include <cstdio> #include <algorithm> #define N 20010 using namespace std; struct info{int to,nex,w;}e[N*2]; int n,tot,head[N],sum,f[N],sz[N],d[3],Ans,rt; bool vis[N]; int gcd(int a,int b){return b?gcd(b,a%b):a;} void Link(int u,int v,int w){ e[++tot].to=v,e[tot].w=w,e[tot].nex=head[u];head[u]=tot; } inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void getrt(int u,int fa){ sz[u]=1,f[u]=0; for(int i=head[u];i;i=e[i].nex){ int v=e[i].to; if(v==fa||vis[v]) continue; getrt(v,u); f[u]=max(f[u],sz[v]); sz[u]+=sz[v]; } f[u]=max(f[u],sum-sz[u]); if(f[rt]>f[u]) rt=u; } void getdep(int u,int fa,int ddd){ d[ddd]++; for(int i=head[u];i;i=e[i].nex){ int v=e[i].to; if(v==fa||vis[v]) continue; getdep(v,u,(ddd+e[i].w)%3); } } int calc(int u,int ddd){ d[0]=d[1]=d[2]=0; getdep(u,0,ddd%3); return d[1]*d[2]*2+d[0]*d[0]; } void solve(int u){ Ans+=calc(u,0); vis[u]=1; for(int i=head[u];i;i=e[i].nex){ int v=e[i].to; if(vis[v]) continue; Ans-=calc(v,e[i].w); sum=sz[v]; getrt(v,rt=0); solve(rt); } } int main(){ n=read(); for(int i=1;i<n;++i){ int u=read(),v=read(),w=read(); Link(u,v,w),Link(v,u,w); } sum=n,f[0]=1e9,getrt(1,0); solve(rt); int f=gcd(n*n,Ans); printf("%d/%d\n",Ans/f,n*n/f); return 0; }