bzoj 3451 Normal
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[N],rt;
int son[N]={N},sz[N],sum;bool vis[N];
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[N],top=0,t[N],s[N],h[N],dis[N];
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[N];
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[N];
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;
}
bzoj 3451 Normal的更多相关文章
- bzoj 3451: Tyvj1953 Normal [fft 点分治 期望]
3451: Tyvj1953 Normal 题意: N 个点的树,点分治时等概率地随机选点,代价为当前连通块的顶点数量,求代价的期望值 百年难遇的点分治一遍AC!!! 今天又去翻了一下<具体数学 ...
- 【BZOJ 3451】Tyvj1953 Normal 思维题+期望概率+FFT+点分治
我感觉是很强的一道题……即使我在刷专题,即使我知道这题是fft+点分治,我仍然做不出来……可能是知道是fft+点分治限制了我的思路???(别做梦了,再怎样也想不出来的……)我做这道题的话,一看就想单独 ...
- BZOJ 3451: Tyvj1953 Normal 点分治+FFT
根据期望的线性性,我们算出每个点期望被计算次数,然后进行累加. 考虑点 $x$ 对点 $y$ 产生了贡献,那么说明 $(x,y)$ 之间的点中 $x$ 是第一个被删除的. 这个期望就是 $\frac{ ...
- 3451: Tyvj1953 Normal 点分治 FFT
国际惯例的题面:代价理解为重心和每个点这个点对的代价.根据期望的线性性,我们枚举每个点,计算会产生的ij点对的代价即可.那么,i到j的链上,i必须是第一个被选择的点.对于i来说,就是1/dis(i,j ...
- 值得一做》关于数学与递推 BZOJ1002 (BZOJ第一页计划)(normal+)
什么都不说先甩题目 Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之 ...
- 【BZOJ】【1020】【SHOI2008】安全的航线flight
计算几何/二分/迭代/搜索+剪枝 写三个tag可能是因为从哪个方向来理解都可以吧…… 我完全不会计算几何所以抄了ydc的代码 题解:http://ydcydcy1.blog.163.com/blog/ ...
- BZOJ3451: Tyvj1953 Normal
题解: 好神的一道题.蒟蒻只能膜拜题解. 考虑a对b的贡献,如果a是a-b路径上第一个删除的点,那么给b贡献1. 所以转化之后就是求sigma(1/dist(i,j)),orz!!! 如果不是分母的话 ...
- 【BZOJ3451】Normal (点分治)
[BZOJ3451]Normal (点分治) 题面 BZOJ 题解 显然考虑每个点的贡献.但是发现似乎怎么算都不好计算其在点分树上的深度. 那么考虑一下这个点在点分树中每一次被计算的情况,显然就是其在 ...
- BZOJ.4542.[HNOI2016]大数(莫队)
题目链接 大数除法是很麻烦的,考虑能不能将其条件化简 一段区间[l,r]|p,即num[l,r]|p,类似前缀,记后缀suf[i]表示[i,n]的这段区间代表的数字 于是有 suf[l]-suf[r+ ...
随机推荐
- 团队作业7——第二次项目冲刺(Beta版本计划及安排)
Beta版本冲刺 需要改进完善的功能 1.寻找BUG.并解决问题 2.界面的优化 下一阶段新增的功能' 1.个人信息头像上传 2.头像裁剪功能 需要改进的团队分工 1.之前产品的主要工作 ...
- python functools.lru_cache做备忘功能
import time import functools def clock(func): @functools.wraps(func)#还原被装饰函数的__name__和__doc__属性 def ...
- Django Haystack 全文检索与关键词高亮
Django Haystack 简介 django-haystack 是一个专门提供搜索功能的 django 第三方应用,它支持 Solr.Elasticsearch.Whoosh.Xapian 等多 ...
- const volatile同时限定一个类型int a = 10
const和volatile放在一起的意义在于: (1)本程序段中不能对a作修改,任何修改都是非法的,或者至少是粗心,编译器应该报错,防止这种粗心: (2)另一个程序段则完全有可能修改,因此编译器最好 ...
- 在Windows上安装「算法 第四版」组件
这篇文档将向你介绍如何在Windows系统上安装本书将用到的Java开发环境,同时我们也提供了一个手把手的.使用我们提供的DrJava工具或者用命令行来创建.编译和运行你的第一个Java程序的手册,这 ...
- Flask 扩展 用户会话
pip install flask-login 接下来创建扩展对象实例: from flask import Flask from flask_login import LoginManager ap ...
- pymysql 多字段插入
d = {'name':'alx','age':18,'pp':11,'cc':12} sql = '''insert into xx(%s) value(%s)''' key_list = [] v ...
- linux服务器操作系统,在相同环境下,哪个做lamp服务器更稳定点?哪个版本更稳定?
随着国内WEB服务越来越多,如何才能选择一个合适的linux服务器操作系统?在国内用的最多的好像是红帽子系列也就是red hat系列,但有些版本缺乏稳定性.新手在选择操作系统的时候最好只用偶数版本,还 ...
- DML数据操作语言之增加,删除,更新
1.数据的增加 数据的增加要用到insert语句 ,基本格式是: insert into <表名> (列名1,列名2,列名3,......) values (值1,值2,值3,..... ...
- HTML标签小记文本类标签
文本类标签: <input type="text" name="" value="">文本框 type(方式,方法)name文 ...