bzoj2152 / P2634 [国家集训队]聪聪可可(点分治)
淀粉质点分治板子
边权直接 mod 3
直接点分治统计出所有的符合条件的点对再和总方案数约分
至于约分.....gcd搞搞就好辣
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; inline int Max(int a,int b){return a>b?a:b;} void read(int &x){ static char c=getchar();x=0; while(c<'0'||c>'9') c=getchar(); while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar(); } #define N 20005 inline int M(int x){return x<3?x:x-3;} int n,rt,sum,ans,tot,mxd[N],siz[N],dis[N],ra[N],rb[3];bool vis[N]; int cnt,hd[N],nxt[N<<1],ed[N],poi[N<<1],val[N<<1]; void adde(int x,int y,int v){ nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt; ed[x]=cnt; poi[cnt]=y; val[cnt]=v; } void getrt(int x,int fa){ siz[x]=1; mxd[x]=0; for(int i=hd[x];i;i=nxt[i]){ int to=poi[i]; if(to==fa||vis[to]) continue; getrt(to,x); siz[x]+=siz[to]; mxd[x]=Max(mxd[x],siz[to]); }mxd[x]=Max(mxd[x],sum-siz[x]); if(mxd[x]<mxd[rt]) rt=x; } void getdis(int x,int fa){ ra[++ra[0]]=dis[x]; for(int i=hd[x];i;i=nxt[i]){ int to=poi[i]; if(to==fa||vis[to]) continue; dis[to]=M(dis[x]+val[i]); getdis(to,x); } } void calc(int x){ rb[0]=1; for(int i=hd[x];i;i=nxt[i]){ int to=poi[i]; if(vis[to]) continue; ra[0]=0; dis[to]=val[i]; getdis(to,x); for(int i=ra[0];i;--i) ans+=rb[ra[i]?3-ra[i]:0]; for(int i=ra[0];i;--i) ++rb[ra[i]]; }rb[0]=rb[1]=rb[2]=0; } void solve(int x){ vis[x]=1; calc(x); for(int i=hd[x];i;i=nxt[i]){ int to=poi[i]; if(vis[to]) continue; sum=siz[to]; rt=0; getrt(to,x); solve(rt); } } int gcd(int a,int b){return b?gcd(b,a%b):a;} int main(){ read(n); register int i; int q1,q2,q3; for(i=1;i<n;++i){ read(q1),read(q2),read(q3); q3%=3; adde(q1,q2,q3); adde(q2,q1,q3); }mxd[rt=0]=n+1; sum=n; getrt(1,0); solve(rt); ans=ans*2+n; tot=n*n; int g=gcd(ans,tot); ans/=g; tot/=g; printf("%d/%d",ans,tot); return 0; }