bzoj 3451 Normal
2018-04-13 19:57
246 查看
Description
某天WJMZBMR学习了一个神奇的算法:树的点分治!这个算法的核心是这样的:
消耗时间=0
Solve(树 a)
消耗时间 += a 的 大小
如果 a 中 只有 1 个点
退出
否则在a中选一个点x,在a中删除点x
那么a变成了几个小一点的树,对每个小树递归调用Solve
我们注意到的这个算法的时间复杂度跟选择的点x是密切相关的。
如果x是树的重心,那么时间复杂度就是O(nlogn)
但是由于WJMZBMR比较傻逼,他决定随机在a中选择一个点作为x!
Sevenkplus告诉他这样做的最坏复杂度是O(n^2)
但是WJMZBMR就是不信><。。。
于是Sevenkplus花了几分钟写了一个程序证明了这一点。。。你也试试看吧^^
现在给你一颗树,你能告诉WJMZBMR他的傻逼算法需要的期望消耗时间吗?(消耗时间按在Solve里面的那个为标准)
题面
Solution
考虑一个点会被算入贡献几次,假如我们构出了一棵点分树,那么就贡献了 \(dep\) 次那么我们考虑任意一个点对 \((x,y)\), 只有 \(y\) 在点分树上是 \(x\) 的父亲,才对 \(x\) 有 \(1\) 的贡献
并且 \(y\) 在点分树上是 \(x\) 的父亲的条件是 在原树中 \((x,y)\) 这条路径上的任意一个点都没有在分治到 \(y\) 之前被分治到
又因为一个点被随机的概率是均等的,则可以得出 \(y\) 对 \(x\) 有 \(1\) 的贡献的概率是 \(\frac{1}{dis(x,y)}\)
所以原问题转化为求 \(\sum_{i=1}^{n}\sum_{j=1}^n\frac{1}{dis(x,y)}\)
这个可以用点分治实现
设 \(t[i]\) 表示路径长度为 \(i\) 的点的数量
\(t[i]=\sum_{j=1}^{i}t[i]*t[i-j]\)
这是一个卷积的形式,可以用 \(FFT\) 优化
复杂度 \(O(n*log^2n)\)
#include<bits/stdc++.h> using namespace std; typedef complex<double> dob; const int N=240005;const double pi=acos(-1.0); int n,nxt[N<<1],to[N<<1],num=0,head ,rt; int son ={N},sz ,sum;bool vis ; inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;} inline void getroot(int x,int last){ sz[x]=1;son[x]=0; for(int i=head[x];i;i=nxt[i]){ int u=to[i];if(u==last || vis[u])continue; getroot(u,x); sz[x]+=sz[u];son[x]=max(son[x],sz[u]); } son[x]=max(son[x],sum-sz[x]); if(son[x]<son[rt])rt=x; } int st ,top=0,t ,s ,h ,dis ; inline void dfs(int x,int last,int val){ s[val]++;st[++top]=x;dis[x]=val; for(int i=head[x];i;i=nxt[i]){ int u=to[i];if(u==last || vis[u])continue; dfs(u,x,val+1); } } namespace FFT{ int n,L=0,R ; inline void FFT(dob *A,int o){ for(int i=0;i<n;i++)if(i<R[i])swap(A[i],A[R[i]]); for(int i=1;i<n;i<<=1){ dob wn(cos(pi/i),sin(pi/i*o)),x,y; for(int j=0;j<n;j+=(i<<1)){ dob w(1,0); for(int k=0;k<i;k++,w*=wn){ x=A[j+k];y=w*A[j+k+i]; A[j+k]=x+y;A[j+k+i]=x-y; } } } } inline void mul(dob *A,int len){ for(n=1,L=0;n<=len;n<<=1)L++; for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1)); FFT(A,1); for(int i=0;i<=n;i++)A[i]*=A[i]; FFT(A,-1); A[0]=0;for(int i=1;i<=n;i++)h[i]=(int)(A[i].real()/n+0.5),A[i]=0; } } dob A ; inline void calc(int x,int op,int val){ top=0;dfs(x,x,val+1); int len=(sz[x]+1)<<1; for(int i=1;i<=top;i++)A[dis[st[i]]]=s[dis[st[i]]]; FFT::mul(A,len); for(int i=1;i<=len;i++)t[i]+=h[i+1]*op; for(int i=1;i<=top;i++)s[dis[st[i]]]--; } inline void solve(int x){ vis[x]=1;getroot(x,x);calc(x,1,0); for(int i=head[x];i;i=nxt[i]){ int u=to[i];if(vis[u])continue; getroot(u,x);calc(u,-1,1); rt=0;sum=sz[u];getroot(u,x);solve(rt); } } int main(){ freopen("pp.in","r",stdin); freopen("pp.out","w",stdout); int x,y; scanf("%d",&n); for(int i=1;i<n;i++){ scanf("%d%d",&x,&y);x++;y++; link(x,y);link(y,x); } rt=0;sum=n;getroot(1,1);solve(rt); double ans=0; for(int i=1;i<=n;i++)ans+=1.0*t[i]/i; printf("%.4lf\n",ans); return 0; }
相关文章推荐
- 【BZOJ3451】Tyvj1953 Normal 点分治+FFT+期望
- [BZOJ3451][Tyvj1953]Normal
- bzoj 3451: Tyvj1953 Normal [fft 点分治 期望]
- bzoj 3451: Tyvj1953 Normal
- bzoj 3451: Tyvj1953 Normal 点分治+fft
- 【BZOJ 3451】Tyvj1953 Normal 思维题+期望概率+FFT+点分治
- [bzoj3451]Tyvj1953 Normal
- 【bzoj3451】【Tyvj1953】Normal 题解
- bzoj3451 Tyvj1953 Normal(期望概率+点分治+FFT)
- bzoj 3451
- BZOJ 4435 [双连通分量][Hash]
- bzoj3631: [JLOI2014]松鼠的新家 (树上差分)
- BZOJ1834: [ZJOI2010]network 网络扩容
- [BZOJ4316][仙人掌][DP]小C的独立集
- BZOJ3392: [Usaco2005 Feb]Part Acquisition 交易
- BZOJ 3931 CQOI 2015 网络吞吐量 最短路+最大流
- [bzoj1826] [JSOI2010]缓存交换
- BZOJ2769 : YY的快速排序
- (树直径) bzoj 1509
- bzoj 2763: [JLOI2011]飞行路线 分层图