2018.12.08【BZOJ2152】聪聪可可(树形DP)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/84892509

传送门


解析:

维护从子树内到该节点上有多少条路径模3余0,1,2就行了。

统计考虑以每个点为 l c a lca 的路径有多少条满足条件。

(其实这道题可以点分治)


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
	return num;
}

cs int N=20004;
int last[N],nxt[N<<1],to[N<<1],ecnt;
int w[N<<1];
inline void addedge(int u,int v,int val){
	nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
	nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,w[ecnt]=val;
}

int ans;
int f[N][3];
inline void dfs(int u,int fa){
	++f[u][0];
	for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
		if(v==fa)continue;
		dfs(v,u);
		for(int re i=0;i<3;++i)ans+=f[u][i]*f[v][(6-i-w[e])%3];
		for(int re i=0;i<3;++i)f[u][i]+=f[v][(i+3-w[e])%3];
	}
}

int n;
signed main(){
	n=getint();
	for(int re i=1;i<n;++i){
		re int u=getint(),v=getint(),w=getint();
		addedge(u,v,w%3);
	}
	dfs(1,0);
	ans=ans*2+n;
	re int g=__gcd(ans,n*n);
	printf("%d/%d",ans/g,n*n/g);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/84892509