[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;
}

 

posted @ 2018-05-29 19:40  void_f  阅读(127)  评论(0编辑  收藏  举报