题解:
还好。。。看懂题目就好做了。(Orzdyh)
首先选择的点是等概率随机的,也就是说每种选择结果的概率都是一样的,所以选择一个点的时候已经选择的点不会有影响,那么就可以直接算出点对个数再求总体的期望。具体来说,每条边会在$\binom{n-2}{\lceil\frac{n}{3}\rceil -1}$种情况中被选择(说不清楚,感性理解一下),再除以总的情况数$\binom{n}{\lceil\frac{n}{3}\rceil}$即可,这一步可以约分,注意要对$n\mod 3$的余数分类讨论。
前面的部分是点分治经典应用,就不说了。我貌似写的很挫,第一次有三个点T了20ms,其他人一共就跑了20ms。。。第二次加了读入优化999ms过了。。。妙不可言
代码:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 #define eps 1e-9
9 using namespace std;
10 typedef long long ll;
11 struct edge{
12 int v,next;
13 }a[100001];
14 int n,m,u,v,lk[11],anss[11],sum=0,S,rt,tot=0,cnt=0,head[50001],siz[50001],mx[50001],dis[50001];
15 bool used[50001];
16 double ans1,ans2;
17 char buffer[1000010],*hd,*tl;
18 inline char Getchar(){
19 if(hd==tl){
20 int len=fread(buffer,1,1000000,stdin);
21 hd=buffer,tl=hd+len;
22 if(hd==tl)
23 return EOF;
24 }
25 return *hd++;
26 }
27 inline int rd(){
28 register int x=0;
29 char c;
30 do c=Getchar();
31 while(!isdigit(c));
32 do{
33 x=(x<<1)+(x<<3)+(c^48);
34 c=Getchar();
35 }while(isdigit(c));
36 return x;
37 }
38 inline void add(int u,int v){
39 a[++tot].v=v;
40 a[tot].next=head[u];
41 head[u]=tot;
42 }
43 inline void dfsrt(int u,int ff){
44 siz[u]=1;
45 mx[u]=0;
46 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
47 int v=a[tmp].v;
48 if(v!=ff&&!used[v]){
49 dfsrt(v,u);
50 mx[u]=max(mx[u],siz[v]);
51 siz[u]+=siz[v];
52 }
53 }
54 mx[u]=max(mx[u],S-siz[u]);
55 if(mx[u]<mx[rt])rt=u;
56 }
57 inline void getdis(int u,int fa,int ds){
58 dis[++cnt]=ds;
59 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
60 int v=a[tmp].v;
61 if(v!=fa&&!used[v])getdis(v,u,ds+1);
62 }
63 }
64 inline int gao1(int l,int r,int k){
65 int ret=-1;
66 while(l<=r){
67 int mid=(l+r)/2;
68 if(dis[mid]==k)ret=mid,l=mid+1;
69 else if(dis[mid]<k)l=mid+1;
70 else r=mid-1;
71 }
72 return ret;
73 }
74 inline int gao2(int l,int r,int k){
75 int ret=0;
76 while(l<=r){
77 int mid=(l+r)/2;
78 if(dis[mid]==k)ret=mid,r=mid-1;
79 else if(dis[mid]<k)l=mid+1;
80 else r=mid-1;
81 }
82 return ret;
83 }
84 inline int calc(int u,int w,int K){
85 cnt=0;
86 getdis(u,0,w);
87 sort(dis+1,dis+cnt+1);
88 //for(int i=1;i<=cnt;i++)printf("%d ",dis[i]);
89 //printf("\n");
90 int ret=0;
91 for(int i=1;i<=cnt;i++){
92 if(dis[i]*2>K)break;
93 ret+=gao1(i,cnt,K-dis[i])-gao2(i,cnt,K-dis[i])+1;
94 }
95 return ret;
96 }
97 inline void divide(int u){
98 used[u]=true;
99 for(int i=1;i<=m;i++)anss[i]+=calc(u,0,lk[i]);
100 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
101 int v=a[tmp].v;
102 if(!used[v]){
103 for(int i=1;i<=m;i++){
104 anss[i]-=calc(v,1,lk[i]);
105 }
106 S=siz[v],rt=0;
107 dfsrt(v,0);
108 divide(rt);
109 }
110 }
111 }
112 int main(){
113 memset(head,-1,sizeof(head));
114 memset(anss,0,sizeof(anss));
115 //scanf("%d%d",&n,&m);
116 n=rd(),m=rd();
117 for(int i=1;i<=m;i++)lk[i]=rd();//scanf("%d",&lk[i]);
118 for(int i=1;i<n;i++){
119 //scanf("%d%d",&u,&v);
120 u=rd();
121 v=rd();
122 add(u,v);
123 add(v,u);
124 }
125 S=n,mx[rt=0]=2333333;
126 dfsrt(1,0);
127 divide(rt);
128 //for(int i=1;i<=m;i++)printf("%d ",anss[i]);
129 for(int i=1;i<=m;i++)sum+=anss[i];
130 if(n%3==1||n%3==2){
131 ans1=(double)((double)sum*(n/3)*(n/3+1))/(double)((double)n*(n-1));
132 if(n%3==1)printf("%.2lf\n",ans1);
133 else printf("%.2lf\n%.2lf\n",ans1,ans1);
134 }
135 ans2=(double)((double)sum*(n/3)*(n/3-1))/(double)((double)n*(n-1));
136 if(n%3==0)printf("%.2lf\n%.2lf\n%.2lf",ans2,ans2,ans2);
137 else if(n%3==1)printf("%.2lf\n%.2lf",ans2,ans2);
138 else printf("%.2lf",ans2);
139 return 0;
140 }