BZOJ3451 Tyvj1953 Normal

来源:互联网 发布:linux c语言多线程 编辑:程序博客网 时间:2024/06/01 21:51

由期望的线性性(日常%xuruifan)答案等于每个点的期望被算的次数之和,考虑每个点x会被算多少次,首先最开始肯定会被算一次,而如果另一个点y被选中了,并且x到y的路径上没有别的被选中的点,即y是x到y路径上第一个被选中的点,那么答案会+1

每个点作为路径上第一给被选中的点的概率是一样的,所以答案是sigma 1/dis(i,j)(注意点对是有序的)

所以求出每个长度的路径的条数就可以了

可以点分治+FFT

关于复杂度,我们知道点分治一般有两种写法,一种是对于当前重心,每次搜他的一个子树,把这个子树的信息与已经搜过的子树的信息合并,另一种是直接搜当前分治的子树,更新答案然后搜重心的每个儿子的子树,把不合法的路径取得

这道题如果我们采用第一种方法那么复杂度就是n^2 log^2n 的,而采用第二种方法就是n log^2 n的(真tm玄学,复杂度证明orz ljss)

证明:如果采用第一种方法,对于每层的每个子树,设s为子树大小,FFT的总长度是子树最大深度×根节点儿子个数=O(s^2)的,而如果用第二种方法,对于每层的每个子树,FFT的总长度是最大深度+每个儿子子树的高度=O(s)的,所以第二种方法是n log^2 n而第一种方法是n^2 log n

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<ctime>#include<cmath>#include<algorithm>#include<iomanip>#include<vector>#include<map>#include<set>#include<bitset>#include<queue>#include<stack>using namespace std;#define MAXN 60010#define MAXM 1010#define INF 1000000000#define MOD 1000000007#define eps 1e-8#define ll long longconst double pi=acos(-1);struct vec{int to;int fro;};struct cl{double x;double y;cl(){}cl(double _x,double _y){x=_x;y=_y;}friend cl operator +(cl x,cl y){return cl(x.x+y.x,x.y+y.y);}friend cl operator -(cl x,cl y){return cl(x.x-y.x,x.y-y.y);}friend cl operator *(cl x,cl y){return cl(x.x*y.x-x.y*y.y,x.y*y.x+x.x*y.y);}friend cl operator /(cl x,double y){return cl(x.x/y,x.y/y);}};vec mp[MAXN];int tai[MAXN],cnt;int siz[MAXN],bal[MAXN];ll ans[MAXN];bool vis[MAXN];int tim[MAXN];int sum,rt,rtf;int n;int m;int T;int c[MAXN];int L,R[MAXN];cl a[MAXN];double ANS;inline void be(int x,int y){mp[++cnt].to=y;mp[cnt].fro=tai[x];tai[x]=cnt;}inline void bde(int x,int y){be(x,y);be(y,x);}void getrt(int x,int f){int i,y;siz[x]=1;bal[x]=0;for(i=tai[x];i;i=mp[i].fro){y=mp[i].to;if(!vis[y]&&y!=f){getrt(y,x);siz[x]+=siz[y];bal[x]=max(bal[x],siz[y]);}}bal[x]=max(bal[x],sum-siz[x]);if(bal[x]<bal[rt]){rt=x;rtf=f;}}void dfs(int x,int f,int d){int i,y;if(tim[d]!=T){c[d]=0;}c[d]++;tim[d]=T;m=max(m,d);for(i=tai[x];i;i=mp[i].fro){y=mp[i].to;if(y!=f&&!vis[y]){dfs(y,x,d+1);}}}void fft(cl *a,int f){int i,j,k;for(i=0;i<m;i++){if(i<R[i]){swap(a[i],a[R[i]]);}}for(i=1;i<m;i<<=1){cl wn(cos(pi/i),f*sin(pi/i));for(j=0;j<m;j+=(i<<1)){cl w(1,0);for(k=0;k<i;k++,w=w*wn){cl x=a[j+k],y=w*a[j+k+i];a[j+k]=x+y;a[j+k+i]=x-y;}}}if(f==-1){for(i=0;i<m;i++){a[i]=a[i]/m;}}}void cal(int f){int i;int M=m<<1;L=0;for(m=1;m<=M;m<<=1){L++;}for(i=0;i<m;i++){R[i]=R[i>>1]>>1|((i&1)<<(L-1));}for(i=0;i<m;i++){if(tim[i]!=T){c[i]=0;}a[i].x=c[i];a[i].y=0;}fft(a,1);for(i=0;i<m;i++){a[i]=a[i]*a[i];}fft(a,-1);for(i=0;i<min(n,m);i++){ans[i]+=(ll)(a[i].x+0.1)*f;}}void work(int x){int i,y;vis[x]=1;m=0;T++;dfs(x,0,0);cal(1);for(i=tai[x];i;i=mp[i].fro){y=mp[i].to;if(!vis[y]){m=0;T++;dfs(y,0,1);cal(-1);sum=siz[y];rt=0;getrt(y,0);siz[rtf]=sum-siz[rt];work(rt);}}}int main(){int i,x,y;bal[0]=INF;scanf("%d",&n);for(i=1;i<n;i++){scanf("%d%d",&x,&y);x++;y++;bde(x,y);}sum=n;getrt(1,0);siz[rtf]=sum-siz[rt];work(rt);for(i=0;i<=n-1;i++){ANS+=1.0*ans[i]/(i+1);}printf("%.4lf\n",ANS);return 0;}/*50 11 21 30 430 11 2*/


0 0
原创粉丝点击