原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ3451.html

题目传送门 - BZOJ3451

题意

  给定一棵有 $n$ 个节点的树,在树上随机点分治,问消耗时间的期望。

  计算点分治耗时由如下函数给出:

Time = 0
Solve( T ){
Time += |T|
if ( |T| = 1 ) then
return ;
x = 一个随机节点 in T
for y in {与 x 直接连边的节点 in T} do
Solve( SubTree y )
}

  $n\leq 3\times 10^4$

题解

  考虑最终在点分树上,如果 $y$ 是 $x$ 的祖先,那么就会产生一点贡献。我们把它记为:数对 $(x,y)$ 产生了一点贡献。

  回到原树,如果数对 $(x,y)$ 能产生贡献,那么 $y$ 一定是 $x$ 到 $y$ 路径上面最先被选中的。因为, $x$ 显然不能先选,而如果选择了 $x$ 到 $y$ 之间的节点,那么 $x$ 和 $y$ 在点分树中就被分到了两个子树中,不能产生贡献。

  由于是等概率随机选点,所以对于任何两个点 $(x,y)$ ,$y$ 最先被选中的概率显然是 $\cfrac{1}{dis(x,y)}$ 。

  所以,答案被转化为:

$$\sum_{i=1}^{n}\sum_{j=1}^{n}\cfrac{1}{dis(x,y)}$$

  于是我们就可以 点分治 + FFT 了。

  具体地:

  我们需要得到每一个长度的路径条数。

  对于每一个点分中心,我们先分治处理所有子树。

  然后,dfs 遍历所有子树,对于每一个子树得到子树内的深度值的情况。注意,用 vector 存。

  然后,任意两个子树的信息就可以合并了。

  但是暴力合并显然是不对的,$n^2$ 复杂度肯定超时。(下面把子树深度数组当作多项式)

  考虑将子树按照最深深度排序,从深度小到深度大,通过多项式前缀和一下,FFT 优化多项式乘法即可。

  再具体??看代码吧……

  时间复杂度 $O(n\log^2 n)$ 。

代码

#include <bits/stdc++.h>
using namespace std;
int read(){
int x=0;
char ch=getchar();
while (!isdigit(ch))
ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x;
}
const int N=30005;
struct Gragh{
static const int M=N*2;
int cnt,y[M],nxt[M],fst[N];
void clear(){
cnt=0;
memset(fst,0,sizeof fst);
}
void add(int a,int b){
y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
}
}g;
int Pow(int x,int y,int mod){
int ans=1;
for (;y;y>>=1,x=1LL*x*x%mod)
if (y&1)
ans=1LL*ans*x%mod;
return ans;
}
namespace FaFaTa{
static const int N=1<<15,mod=998244353;
int n,d;
int w[N],R[N],A[N],B[N];
vector <int> res;
void FFT(int a[],int n){
for (int i=0;i<n;i++)
if (R[i]<i)
swap(a[i],a[R[i]]);
for (int d=1,t=n>>1;d<n;d<<=1,t>>=1)
for (int i=0;i<n;i+=(d<<1))
for (int j=0;j<d;j++){
int tmp=1LL*w[t*j]*a[i+j+d]%mod;
a[i+j+d]=(a[i+j]-tmp+mod)%mod;
a[i+j]=(a[i+j]+tmp)%mod;
}
}
void FFT_Mul(vector <int> &a,vector <int> &b){
int la=a.size(),lb=b.size();
for (n=1,d=0;n<la+lb-1;n<<=1,d++);
for (int i=0;i<n;i++)
R[i]=(R[i>>1]>>1)|((i&1)<<(d-1));
w[0]=1,w[1]=Pow(3,(mod-1)/n,mod);
for (int i=2;i<n;i++)
w[i]=1LL*w[i-1]*w[1]%mod;
for (int i=0;i<n;i++)
A[i]=i<la?a[i]:0;
for (int i=0;i<n;i++)
B[i]=i<lb?b[i]:0;
FFT(A,n),FFT(B,n);
for (int i=0;i<n;i++)
A[i]=1LL*A[i]*B[i]%mod;
w[1]=Pow(w[1],mod-2,mod);
for (int i=2;i<n;i++)
w[i]=1LL*w[i-1]*w[1]%mod;
FFT(A,n);
int inv=Pow(n,mod-2,mod);
for (int i=0;i<n;i++)
A[i]=1LL*A[i]*inv%mod;
res.clear();
for (int i=0;i<n;i++)
res.push_back(A[i]);
}
}
int n,Time;
int ans[N],vis[N],size[N],Max[N],root;
int id[N],id_cnt,dcnt[N];
vector <int> depth[N];
void Get_root(int x,int pre){
id[++id_cnt]=x;
size[x]=1,Max[x]=0;
for (int i=g.fst[x];i;i=g.nxt[i])
if (g.y[i]!=pre&&!vis[g.y[i]]){
Get_root(g.y[i],x);
size[x]+=size[g.y[i]];
Max[x]=max(Max[x],size[g.y[i]]);
}
}
void Get_depth(int rt,int y,int x,int pre,int d){
if (depth[y].size()<=0.1+d)
depth[y].push_back(0);
depth[y][d]++;
for (int i=g.fst[x];i;i=g.nxt[i])
if (g.y[i]!=pre&&vis[rt]<vis[g.y[i]])
Get_depth(rt,y,g.y[i],x,d+1);
}
bool cmp(int a,int b){
return depth[a].size()<depth[b].size();
}
void solve(int root){
id_cnt=0;
Get_root(root,0);
int n=size[root],x=root;
for (int i=1;i<=id_cnt;i++){
int y=id[i];
Max[y]=max(Max[y],n-size[y]);
if (Max[y]<Max[x])
x=y;
}
vis[x]=++Time;
for (int i=g.fst[x];i;i=g.nxt[i])
if (!vis[g.y[i]])
solve(g.y[i]);
id_cnt=0;
for (int i=g.fst[x];i;i=g.nxt[i])
if (vis[g.y[i]]>vis[x]){
int y=id[++id_cnt]=g.y[i];
depth[y].clear();
depth[y].push_back(0);
Get_depth(x,y,y,x,1);
}
sort(id+1,id+id_cnt+1,cmp);
depth[id[0]=0].clear();
depth[0].push_back(1);
for (int i=1;i<=id_cnt;i++){
FaFaTa :: FFT_Mul(depth[id[i-1]],depth[id[i]]);
for (int j=0;j<FaFaTa :: n;j++)
ans[j]+=FaFaTa :: res[j];
for (int j=0;j<depth[id[i-1]].size();j++)
depth[id[i]][j]+=depth[id[i-1]][j];
}
}
int main(){
n=read();
g.clear();
for (int i=1,a,b;i<n;i++){
a=read()+1,b=read()+1;
g.add(a,b);
g.add(b,a);
}
memset(ans,0,sizeof ans);
memset(vis,0,sizeof vis);
Time=0;
solve(1);
long double tot=n;
for (int i=1;i<n;i++)
tot+=((long double)ans[i])*2/(i+1);
printf("%.4Lf",tot);
return 0;
}

  

BZOJ3451 Tyvj1953 Normal 点分治 多项式 FFT的更多相关文章

  1. [BZOJ3451][Tyvj1953]Normal(点分治+FFT)

    https://www.cnblogs.com/GXZlegend/p/8611948.html #include<cmath> #include<cstdio> #inclu ...

  2. 【BZOJ3451】Tyvj1953 Normal 点分治+FFT+期望

    [BZOJ3451]Tyvj1953 Normal Description 某天WJMZBMR学习了一个神奇的算法:树的点分治!这个算法的核心是这样的:消耗时间=0Solve(树 a) 消耗时间 += ...

  3. BZOJ3451: Tyvj1953 Normal

    题解: 好神的一道题.蒟蒻只能膜拜题解. 考虑a对b的贡献,如果a是a-b路径上第一个删除的点,那么给b贡献1. 所以转化之后就是求sigma(1/dist(i,j)),orz!!! 如果不是分母的话 ...

  4. 【BZOJ3451】Tyvj1953 Normal - 点分治+FFT

    题目来源:NOI2019模拟测试赛(七) 非原题面,题意有略微区别 题意: 吐槽: 心态崩了. 好不容易场上想出一题正解,写了三个小时结果写了个假的点分治,卡成$O(n^2)$ 我退役吧. 题解: 原 ...

  5. 3451: Tyvj1953 Normal 点分治 FFT

    国际惯例的题面:代价理解为重心和每个点这个点对的代价.根据期望的线性性,我们枚举每个点,计算会产生的ij点对的代价即可.那么,i到j的链上,i必须是第一个被选择的点.对于i来说,就是1/dis(i,j ...

  6. BZOJ3451 Tyvj1953 Normal 【期望 + 点分治 + NTT】

    题目链接 BZOJ3451 题解 考虑每个点产生的贡献,即为该点在点分树中的深度期望值 由于期望的线性,最后的答案就是每个点贡献之和 对于点对\((i,j)\),考虑\(j\)成为\(i\)祖先的概率 ...

  7. BZOJ 3451: Tyvj1953 Normal 点分治+FFT

    根据期望的线性性,我们算出每个点期望被计算次数,然后进行累加. 考虑点 $x$ 对点 $y$ 产生了贡献,那么说明 $(x,y)$ 之间的点中 $x$ 是第一个被删除的. 这个期望就是 $\frac{ ...

  8. CodeForces 958F3 Lightsabers (hard) 启发式合并/分治 多项式 FFT

    原文链接http://www.cnblogs.com/zhouzhendong/p/8835443.html 题目传送门 - CodeForces 958F3 题意 有$n$个球,球有$m$种颜色,分 ...

  9. UOJ#23. 【UR #1】跳蚤国王下江南 仙人掌 Tarjan 点双 圆方树 点分治 多项式 FFT

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ23.html 题目传送门 - UOJ#23 题意 给定一个有 n 个节点的仙人掌(可能有重边). 对于所有 ...

随机推荐

  1. C#如何使用SqlCacheDependency

    1.数据库依赖类SqlCacheDependency 数据库缓存依赖主要解决的是当数据库的内容发生改变时,如何及时通知缓存,并更新缓存中的数据的问题. 语法定义: SqlCacheDependency ...

  2. 前端 ----关于DOM的操作的相关实例

    关于DOM操作的相关案例   1.模态框案例 需求: 打开网页时有一个普通的按钮,点击当前按钮显示一个背景图,中心并弹出一个弹出框,点击X的时候会关闭当前的模态框 代码如下: <!DOCTYPE ...

  3. 安装elasticsearch 5.x, 6.x 常见问题(坑)的解决

    本人在elasticsearch 5.x, 6.x 安装过程中遇到了一些问题: 警告提示 [2016-11-06T16:27:21,712][WARN ][o.e.b.JNANatives ] una ...

  4. Swift 设置某个对象的normal 属性找不到normal 解决方案

    normal  等价于 UIControlState(rawValue: 0)

  5. poj1094 恶心题,,每次加边进行判断

    /* 给定一组偏序关系,问最少第几步能确定次序 如果出现环,问第几步出现环 因为要求第几步确定次序或者第几步出现环,所以每次读入一个偏序关系就进行一次拓扑排序 */ #include <iost ...

  6. MAKEWORD 宏(macro)

    先看看Microsoft给出的关于MAKEWORD的参考: 从Microsoft给出的参考可以得知,宏MAKEWORD的作用是用于创建一个由bHigh和bLow组成的WORD类型的值. 其中bLow是 ...

  7. 支持向量机-SMO算法简化版

    SMO:序列最小优化 SMO算法:将大优化问题分解为多个小优化问题来求解 SMO算法的目标是求出一系列的alpha和b,一旦求出这些alpha,就很容易计算出权重向量w,并得到分隔超平面 工作原理:每 ...

  8. CC攻击原理及防范方法和如何防范CC攻击

    一. CC攻击的原理: CC攻击的原理就是攻击者控制某些主机不停地发大量数据包给对方服务器造成服务器资源耗尽,一直到宕机崩溃.CC主要是用来消耗服务器资源的,每个人都有这样的体验:当一个网页访问的人数 ...

  9. XML使用与总结

    xml是一种比较方便的数据储存方式,它适用于小数据的存储.最常见的适用地方莫过于各种web.config与app.config了.   一.创建一个简单的xml路径 public static str ...

  10. Vuex详解笔记1

    vuex 是什么Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 什么是状态?状态这里泛指 ...