[bzoj2152]聪聪可可(点分治)

题意:在一棵树中,求两点之间距离是3的倍数的概率。

解题关键:$p = \frac{{\sum {nu{m_0}*nu{m_0} + nu{m_1}*nu{m_2}*2} }}{{n*n}}$

求概率分子分母必须对应,分母是无序的,则分子也必须是无序的。

复杂度:$O(n\log n)$

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cstdlib>
  5 #include<iostream>
  6 #include<cmath>
  7 #define inf 0x3f3f3f3f
  8 #define maxn 20004
  9 using namespace std;
 10 typedef long long ll;
 11 int head[maxn],cnt,n,k=3,ans,size,s[maxn],f[maxn],root,depth[maxn],num;//vis代表整体的访问情况,每个dfs不应该只用vis来存储
 12 bool vis[maxn];
 13 ll ans1,ans2,ans3;
 14 struct edge{
 15     int to,w,nxt;
 16 }e[maxn<<1];
 17 void add_edge(int u,int v,int w){
 18     e[cnt].to=v;
 19     e[cnt].w=w;
 20     e[cnt].nxt=head[u];
 21     head[u]=cnt++;
 22 }
 23 
 24 inline int read(){
 25     char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar());
 26     int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=(x<<3)+(x<<1)+ls-'0';
 27     if(k=='-')x=0-x;return x;
 28 }
 29 
 30 void get_root(int u,int fa){//get_root会用到size
 31     s[u]=1;f[u]=0;//f是dp数组
 32     for(int i=head[u];i!=-1;i=e[i].nxt){
 33         int v=e[i].to;
 34         if(v==fa||vis[v]) continue;
 35         get_root(v,u);
 36         s[u]+=s[v];
 37         f[u]=max(f[u],s[v]);
 38     }
 39     f[u]=max(f[u],size-s[u]);
 40     root=f[root]>f[u]?u:root;
 41 }
 42 
 43 void get_depth_size(int u,int fa,int dis){//同时获取size和depth
 44     if(dis%3==0) ans1++;
 45     else if(dis%3==1) ans2++;
 46     else ans3++;
 47     s[u]=1;
 48     for(int i=head[u];i!=-1;i=e[i].nxt){
 49         int v=e[i].to;
 50         if(v==fa||vis[v]) continue;
 51         get_depth_size(v,u,dis+e[i].w);
 52         s[u]+=s[v];
 53     }
 54 }
 55 
 56 int calc(int u,int fa,int w){
 57     ans1=ans2=ans3=0;
 58     get_depth_size(u,fa,w);
 59     return ans1*ans1+ans2*ans3*2;
 60 }
 61 
 62 void work(int u){
 63     vis[u]=true;
 64     ans+=calc(u,-1,0);
 65     for(int i=head[u];i!=-1;i=e[i].nxt){
 66         int v=e[i].to;
 67         if(vis[v]) continue;
 68         ans-=calc(v,u,e[i].w);
 69         size=s[v],root=0;
 70         get_root(v,u);
 71         work(root);
 72     }
 73 }
 74 
 75 void init(){
 76     memset(vis,false, sizeof vis);
 77     memset(head,-1,sizeof head);
 78     ans=cnt=0;
 79 }
 80 
 81 
 82 int main(){
 83     int a,b,c;
 84     f[0]=inf;
 85     while(scanf("%d",&n)!=EOF){
 86         init();
 87         for(int i=0;i<n-1;i++){
 88             a=read(),b=read(),c=read();
 89             add_edge(a,b,c);
 90             add_edge(b,a,c);
 91         }
 92         size=n,root=0;
 93         get_root(1,-1);
 94         work(root);
 95         int gg=__gcd(ans,n*n); 
 96         printf("%d/%d\n",ans/gg,n*n/gg);
 97     }
 98     return 0;
 99     
100 }

 

posted @ 2017-09-08 23:50  Elpsywk  阅读(196)  评论(0编辑  收藏  举报