[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 }