1. 程式人生 > >2018.12.08【BZOJ2152】聰聰可可(樹形DP)

2018.12.08【BZOJ2152】聰聰可可(樹形DP)

傳送門


解析:

維護從子樹內到該節點上有多少條路徑模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; }