[题解] P2634 [国家集训队]聪聪可可

细节

点分治详见:

[图论] 点分治

这个板子有几个细节:

  • 自己到自己也算一条路径

  • 处理好 \(*2\) 或者 不\(*2\) 之间的关系

  • 多测不清空,亲人两行泪

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline int read(){
	char c=getchar();
	int x=0;bool fl=false;
	while(!isdigit(c)){
		if(c=='-')fl=true;
		c=getchar();
	}
	while(isdigit(c)){
		x=(x<<3)+(x<<1)+(c^48);
		c=getchar();
	}
	return fl?-x:x;
}
const int INF = 2147483647;
const int maxn = 2e4 + 5;
int gcd(int a,int b){
	if(!b)return a;
	return gcd(b,a%b);
}
struct edge{
	int to,nxt,w;
}e[maxn<<1];
int head[maxn],cnt=0;
inline void link(int u,int v,int w){
	e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;e[cnt].w=w;
}
int mx[maxn],sz[maxn],S,rt;
bool vis[maxn];
void find_rt(int u,int fa){
	sz[u]=1;mx[u]=0;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(vis[v] || v==fa)continue;
		find_rt(v,u);
		sz[u]+=sz[v];
		mx[u]=max(mx[u],sz[v]);
	}
	mx[u]=max(mx[u],S-sz[u]);
	if(mx[rt]>mx[u])rt=u;
}
int dis[maxn],t[5],now[5];
int dfs(int u,int fa){
	now[dis[u]%3]++;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(vis[v] || v==fa)continue;
		dis[v]=(dis[u]+e[i].w)%3;
		dfs(v,u);
	}
}
int ans=0;
void calc(int u){
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(vis[v])continue;
		for(int j=0;j<3;j++)now[j]=0;
		dis[v]=e[i].w%3;
		dfs(v,u);
		ans+=t[0]*now[0]*2+t[1]*now[2]*2+t[2]*now[1]*2+now[0]*2;
		for(int j=0;j<3;j++)t[j]+=now[j];
	}
}
void solve(int u){
	vis[u]=true;
	calc(u);
	for(int i=0;i<3;i++)t[i]=0;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(vis[v])continue;
		S=sz[v];rt=0;mx[rt]=INF;
		find_rt(v,u);
		solve(rt);
	}
}
int n;
int main(){
	scanf("%d",&n);
	for(int i=1,u,v,w;i<n;i++){
		u=read();v=read();w=read();
		link(u,v,w);link(v,u,w);
	}
	mx[rt=0]=n;
	S=n;
	find_rt(1,0);
	solve(rt);
	ans+=n;
	int g=gcd(ans,n*n);
	printf("%d/%d",ans/g,n*n/g);
	return 0;
}
posted @ 2021-08-12 17:16  ¶凉笙  阅读(6)  评论(0编辑  收藏  举报