Decription:

某天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里面的那个为标准)

n<=30000

大神题,感觉不是特别可想,但貌似还是有一点可想的。

在各种大神引导之下想到了一半,又在他们的引导下颓题解。

关于这道题真的要写一个点分治也是无力吐槽。

题目中有提示啊:算法是$O(n^2)$级别的。(并不代表你的代码可以是$O(n^2)$的)

所以可以考虑每个点对对答案的贡献。(怎么想到的???)

考虑分治过程形成的点分树,如果两个点在点分树上是祖先关系,那么在下面的点就会被多做一次。

否则就不会贡献时间复杂度。

其实消耗的总时间就是所有点在点分树上的期望深度之和。

而两个点在点分树上的关系如何考虑?

如果两个点u,v之间的点的个数为dis(u,v)(含u和v),那么你在这么多个点里第一个选出的点就是u,v在点分树上的LCA。

所以如果你第一次选的是u,那么点对(u,v)就会贡献1答案。选v的话点对(v,u)会贡献答案。选中的概率都是$\frac{1}{dis(u,v)}$。否则均不会贡献答案。

所以总的答案就是$\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{n} \frac{1}{dis(i,j)}$

注意这里的dis是平时说的树上距离再+1,因为是点数而不是边数。

所以现在的问题就转化为了求树上所有点对之间的距离,每个距离值有几种。

经典的点分治。

而时间限制在那里呢,所以合并两个子树的桶值的时候需要用到FFT。

而FFT的大小是根据这个子树深度最大点的深度定的,当然不能跑满啊。

采用的点分治策略是“这棵树内所有点对的距离-子树内重复的贡献”

然后开一个全局的数组不断累加每种距离的出现次数,最后乘以$\frac{1}{i}$即可。

 #include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define S 33333
const double pi=3.141592653589793238;
struct cp{
double r,i;
cp operator*(cp b){return (cp){r*b.r-i*b.i,r*b.i+b.r*i};}
cp operator+(cp b){return (cp){r+b.r,i+b.i};}
cp operator-(cp b){return (cp){r-b.r,i-b.i};}
}a[S<<];
int sz[S],mx=S,tot,fir[S],l[S<<],to[S<<],n,al[S],rt,mxdep,len=,ans[S],rev[S],ec;double Ans;
void FFT(int opt){
for(int i=;i<len;++i)rev[i]=rev[i>>]>>|(i&?len>>:);
for(int i=;i<len;++i)if(rev[i]>i)swap(a[rev[i]],a[i]);
for(int mid=;mid<len;mid<<=){
cp tem=(cp){cos(pi/mid),sin(pi/mid)*opt};
for(int i=;i<len;i+=mid<<){
cp omega=(cp){,};
for(int j=;j<mid;++j,omega=omega*tem){
cp x=a[i+j],y=a[i+j+mid]*omega;
a[i+j]=x+y;a[i+j+mid]=x-y;
}
}
}
}
void con(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
void get_root(int p,int fa){
sz[p]=;int tmx=;
for(int i=fir[p];i;i=l[i])if(to[i]!=fa&&!al[to[i]])get_root(to[i],p),sz[p]+=sz[to[i]],tmx=max(tmx,sz[to[i]]);
tmx=max(tmx,tot-sz[p]);
if(tmx<mx)rt=p,mx=tmx;
}
void get_deep(int p,int fa,int dep){
mxdep=max(mxdep,dep);a[dep].r+=;
for(int i=fir[p];i;i=l[i])if(to[i]!=fa&&!al[to[i]])get_deep(to[i],p,dep+);
}
void cal(int p,int opt){
mxdep=;get_deep(p,,);len=;
while(len<=mxdep<<)len<<=;
FFT();
for(int i=;i<len;++i)a[i]=a[i]*a[i];
FFT(-);
if(opt)for(int i=;i<len;++i)ans[i+]+=int(a[i].r/len+0.1),a[i].r=a[i].i=;
else for(int i=;i<len;++i)ans[i+]-=int(a[i].r/len+0.1),a[i].r=a[i].i=;
}
void dfs(int p){
al[p]=;cal(p,);
for(int i=fir[p];i;i=l[i])if(!al[to[i]])cal(to[i],),tot=sz[to[i]],mx=S,get_root(to[i],p),dfs(rt);
}
int main(){
scanf("%d",&n);
for(int i=,x,y;i<n;++i)scanf("%d%d",&x,&y),con(++x,++y),con(y,x);
tot=n;get_root(,);dfs(rt);
for(int i=;i<=n;++i)Ans+=1.0*ans[i]/i;
printf("%.4lf\n",Ans);
}

神仙题

Tyvj 1953 Normal:多项式,点分治的更多相关文章

  1. 【BZOJ3451】Normal (点分治)

    [BZOJ3451]Normal (点分治) 题面 BZOJ 题解 显然考虑每个点的贡献.但是发现似乎怎么算都不好计算其在点分树上的深度. 那么考虑一下这个点在点分树中每一次被计算的情况,显然就是其在 ...

  2. bzoj 3451: Tyvj1953 Normal [fft 点分治 期望]

    3451: Tyvj1953 Normal 题意: N 个点的树,点分治时等概率地随机选点,代价为当前连通块的顶点数量,求代价的期望值 百年难遇的点分治一遍AC!!! 今天又去翻了一下<具体数学 ...

  3. CodeForces 553E Kyoya and Train 动态规划 多项式 FFT 分治

    原文链接http://www.cnblogs.com/zhouzhendong/p/8847145.html 题目传送门 - CodeForces 553E 题意 一个有$n$个节点$m$条边的有向图 ...

  4. [bzoj3456]城市规划:多项式,分治

    Description 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或 ...

  5. [题解] BZOJ 3456 洛谷 P4841 [集训队作业2013]城市规划 多项式,分治FFT

    题目 令\(f_i\)表示n个点的答案.考虑容斥,用所有连边方案减去有多个连通块的方案.枚举1号点所在的连通块大小: \(f_i=2^{i(i-1)/2}-\sum_{j>0}^{i-1}f_j ...

  6. 多项式细节梳理&模板(多项式)

    基础 很久以前的多项式总结 现在的码风又变了... FFT和NTT的板子 typedef complex<double> C; const double PI=acos(-1); void ...

  7. 【luoguP4721】分治 FFT

    description 给定长度为\(n-1\)的数组\(g[1],g[2],..,g[n-1]\),求\(f[0],f[1],..,f[n-1]\),其中 \[f[i]=\sum_{j=1}^if[ ...

  8. FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅰ

    众所周知,tzc 在 2019 年(12 月 31 日)就第一次开始接触多项式相关算法,可到 2021 年(1 月 1 日)才开始写这篇 blog. 感觉自己开了个大坑( 多项式 多项式乘法 好吧这个 ...

  9. FFT

    void FFT(complex a[],int n,int fl){ ,j=n/;i<n;i++){ if (i<j) {complex t=a[i];a[i]=a[j];a[j]=t; ...

随机推荐

  1. 你不会还在用这8个错误的SQL写法吧?

    1.LIMIT 语句 分页查询是最常用的场景之一,但也通常也是最容易出问题的地方.比如对于下面简单的语句,一般 DBA 想到的办法是在 type, name, create_time 字段上加组合索引 ...

  2. OS OSTEP (Operating Systems Three Easy pieces 操作系统导论 )

    读<OSTEP>的一点重点记录与感悟 (未完) Chapter-2 第二章 1. 操作系统的设计目标:  抽象.高性能.保护.不间断运行. 抽象:建立一些“抽象”,让操作系统方便和易于使用 ...

  3. CCF-CSP题解 201412-4 最优灌溉

    \(kruskal\),有兴趣\(heap\_prim\).\(stl\ pq\)实现复杂度相同. #include <bits/stdc++.h> using namespace std ...

  4. HYSBZ 1040 骑士 (基环外向树DP)

    Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里,在和平环境中 ...

  5. 01-EF Core笔记之创建模型

    使用EF Core的第一步是创建数据模型,模型建的好,下班走的早.EF Core本身已经设置了一系列约定来帮我们快速的创建模型,例如表名.主键字段等,毕竟约定大于配置嘛.如果你想改变默认值,很简单,E ...

  6. centos7安装python3.7.4

    yum install gcc make zlib  zlib-devel openssl openssl-devel libffi-devel bzip2-devel ncurses-devel g ...

  7. Mac OS X 快速添加新文件

    本文为 automator (中文名为 自动操作)的练习之作,尚有许多不足. 如果你想在 OS X 系统中快速添加新文件可直接参考此文 简介 本文使用 automator 创建了一个应用程序 auto ...

  8. Linux 终端(TTY)

    TTY 是 Teletype 或 Teletypewriter 的缩写,原来是指电传打字机,后来这种设备逐渐键盘和显示器取代.不管是电传打字机还是键盘显示器,都是作为计算机的终端设备存在的,所以 TT ...

  9. c++11多线程笔记

    1 thread类thread f;线程等待join()线程分离detach() thread类不可拷贝复制 std::this_thread::yield(); 2 bind 与lambda表达式 ...

  10. 利用PyInstaller打包exe文件

    前言 平常我们通过Python写完一些小脚本之后,如果使用不频繁的话,一般会选择在DOS界面直接跑脚本,或者在IDE中运行.但当我们需要频繁使用某些脚本,或者在没有Python环境的机器上也能顺利运行 ...