BZOJ 2152 聪聪可可(点分治)
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2152
【题目大意】
给出一棵树,问任取两点之间距离为3的倍数的概率是多少
【题解】
树分治统计模3之后不同的链长计算答案,最后和总数求个gcd化简即可。
【代码】
#include <cstdio> #include <algorithm> #include <vector> #include <cstring> using namespace std; typedef pair<int,int> P; #define ff first #define ss second const int N=20010; int n,cnt,ans,root,sum; int size[N],dp[N],d[N],t[5],vis[N]; vector<P> G[N]; void add_edge(int u,int v,int w){ G[u].push_back(P(v,w)); G[v].push_back(P(u,w)); } void getroot(int x,int fx){ size[x]=1; dp[x]=0; for(int i=0;i<G[x].size();i++){ int y=G[x][i].ff,z=G[x][i].ss; if(!vis[y]&&y!=fx){ getroot(y,x); size[x]+=size[y]; dp[x]=max(dp[x],size[y]); } }dp[x]=max(dp[x],sum-size[x]); if(dp[x]<dp[root])root=x; } void getdeep(int x,int fx){ t[d[x]]++; for(int i=0;i<G[x].size();i++){ int y=G[x][i].ff,z=G[x][i].ss; if(!vis[y]&&y!=fx){ d[y]=(d[x]+z)%3; getdeep(y,x); } } } int cal(int x,int dx){ t[0]=t[1]=t[2]=0; d[x]=dx; getdeep(x,0); return t[1]*t[2]*2+t[0]*t[0]; } void solve(int x){ ans+=cal(x,0); vis[x]=1; for(int i=0;i<G[x].size();i++){ int y=G[x][i].ff,z=G[x][i].ss; if(!vis[y]){ ans-=cal(y,z); root=0;sum=size[y]; getroot(y,0); solve(root); } } } int main(){ while(~scanf("%d",&n)){ for(int i=1;i<=n;i++)G[i].clear(); for(int i=1;i<n;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add_edge(u,v,w%3); }dp[0]=sum=n; ans=0; memset(vis,0,sizeof(vis)); getroot(1,0); solve(root); int t=__gcd(ans,n*n); printf("%d/%d\n",ans/t,n*n/t); }return 0; }
愿你出走半生,归来仍是少年