点分治模板题
注意calc计算的时候 注意一个端点经过x的链也是要统计的!!
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v) memset(A,v,sizeof A)
//////////////////////////////////
const int N=2e6+10;
int n,m,cnt,d[N],head[N],pos,siz[N],sum,x,y,z,ans,vis[N],t[5],root,maxson[N];
struct Edge{int to,nex,v;}edge[N<<1];
void add(int a,int b,int c){edge[++pos]=(Edge){b,head[a],c};head[a]=pos;}
void getroot(int x,int fa)
{
siz[x]=1;maxson[x]=0;
for(int i=head[x];i;i=edge[i].nex)
{
int v=edge[i].to;
if(vis[v]||v==fa)continue;
getroot(v,x);siz[x]+=siz[v];
maxson[x]=max(maxson[x],siz[v]);
}
maxson[x]=max(maxson[x],sum-siz[x]);
if(maxson[x]<maxson[root])root=x;
}
void getdis(int x,int fa)
{
t[d[x]]++;
for(int i=head[x];i;i=edge[i].nex)
{
int v=edge[i].to;
if(vis[v]||v==fa)continue;
d[v]=(d[x]+edge[i].v)%3;
getdis(v,x);
}
}
int calc(int x,int v)
{
t[0]=t[1]=t[2]=0;
d[x]=v%3;
getdis(x,0);
return t[0]*t[0]+t[1]*t[2]*2;
}
void solve(int x)
{
see(x);
vis[x]=1;ans+=calc(x,0);
for(int i=head[x];i;i=edge[i].nex)
{
int v=edge[i].to;
if(vis[v])continue;
ans-=calc(v,edge[i].v);
root=0;sum=siz[v];
getroot(v,x);
solve(root);
}
}
int main()
{
scanf("%d",&n);
rep(i,1,n-1)
scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
sum=maxson[0]=n;//一定要初始化 为了每次求根的时候的初始化
root=0;
getroot(1,0);
solve(root);
printf("%d/%d\n",ans/__gcd(n*n,ans),n*n/__gcd(n*n,ans));
return 0;
}
知识兔View Code