[国家集训队]聪聪可可

题目

求出\(mod\ 3=0\)的路径条数,乘\(2\)\(n\)除以\(n^2\)就是答案

点分治就好了

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 20005
#define re register
#define inf 99999999
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
	int x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt,w;}e[maxn<<1];
int n,m,num,tot,S,now,rt;LL ans=0;
int head[maxn],vis[maxn],d[maxn],tax[3],sum[maxn],mx[maxn];
inline void add(int x,int y,int z) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=z;}
inline LL gcd(LL a,LL b) {if(!b) return a;return gcd(b,a%b);}
void getroot(int x,int fa) {
	sum[x]=1,mx[x]=0;
	for(re int i=head[x];i;i=e[i].nxt) {
		if(vis[e[i].v]||e[i].v==fa) continue;
		getroot(e[i].v,x);
		sum[x]+=sum[e[i].v],mx[x]=max(mx[x],sum[e[i].v]);
	}
	mx[x]=max(mx[x],S-sum[x]);
	if(mx[x]<now) now=mx[x],rt=x;
}
void getdis(int x,int fa,int L) {
	d[++tot]=(L%3);
	for(re int i=head[x];i;i=e[i].nxt) {
		if(vis[e[i].v]||e[i].v==fa) continue;
		getdis(e[i].v,x,L+e[i].w);
	}
}
void dfs(int x) {
	vis[x]=1;
	for(re int i=head[x];i;i=e[i].nxt) {
		if(vis[e[i].v]) continue;
		tot=0;getdis(e[i].v,0,e[i].w);
		for(re int j=1;j<=tot;j++) ans+=(d[j]==0),ans+=tax[(3-d[j])%3];
		for(re int j=1;j<=tot;j++) tax[d[j]]++;
	}
	tax[0]=tax[1]=tax[2]=0;
	for(re int i=head[x];i;i=e[i].nxt) {
		if(vis[e[i].v]) continue;
		S=sum[e[i].v],now=inf,getroot(e[i].v,0),dfs(rt);
	}
}
int main() {
	n=read();int x,y,z;
	for(re int i=1;i<n;i++) x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
	S=n,now=inf,getroot(1,0);dfs(rt);
	ans*=2ll;ans+=n;
	LL r=gcd(ans,(LL)n*(LL)n);
	printf("%lld/%lld\n",ans/r,(LL)n*(LL)n/r);
	return 0;
}
posted @ 2019-02-23 16:12  asuldb  阅读(115)  评论(0编辑  收藏  举报