[bzoj3451]Tyvj1953 Normal

题目大意

点分治过程中每次随机选择分治中心。
求期望复杂度。

期望的线性性

容易知道可以单独考虑每个点的贡献。
对于x和y,我们考虑y能否给x带来1的贡献,即y是否是x在点分树上的祖先。
那么Y必须是x到y上第一个被选择为分治中心的点。
一条路径上每个点成为第一个被选择的点概率均等,因此贡献为 1dis(i,j)
答案就是 ni=1nj=11dis(i,j)
这个怎么求???
我们需要知道每一种路径长度的条数。
那么可以点分治,然后FFT。
注意次数界限要和深度挂钩,否则复杂度不对。
同样要采取容斥的打法,即这一层不考虑计算非法,到下一层再去减。
这样就是两个log。

#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef double db;
const db pi=acos(-1);
const int maxn=120000+10;
struct node{
    db x,y;
    friend node operator +(node a,node b){
        node c;
        c.x=a.x+b.x;c.y=a.y+b.y;
        return c;
    }
    friend node operator -(node a,node b){
        node c;
        c.x=a.x-b.x;c.y=a.y-b.y;
        return c;
    }
    friend node operator *(node a,node b){
        node c;
        c.x=a.x*b.x-a.y*b.y;c.y=a.x*b.y+a.y*b.x;
        return c;
    }
};
node d[maxn],c[maxn],e[maxn],f[maxn],tt[maxn];
int dep[maxn],size[maxn],a[maxn],cnt[maxn];
int h[maxn],go[maxn*2],next[maxn*2];
bool bz[maxn];
int i,j,k,l,t,n,m,tot,top,mx,len;
db ans,ce;
void add(int x,int y){
    go[++tot]=y;
    next[tot]=h[x];
    h[x]=tot;
}
void travel(int x,int y){
    a[++top]=x;
    size[x]=1;
    int t=h[x];
    while (t){
        if (!bz[go[t]]&&go[t]!=y){
            travel(go[t],x);
            size[x]+=size[go[t]];
        }
        t=next[t];
    }
}
void dfs(int x,int y){
    int t=h[x];
    while (t){
        if (!bz[go[t]]&&go[t]!=y){
            dep[go[t]]=dep[x]+1;
            dfs(go[t],x);
        }
        t=next[t];
    }
}
void DFT(node *a,int sig){
    int i;
    fo(i,0,len-1){
        int p=0;
        for (int j=0,tp=i;j<ce;j++,tp/=2) p=(p<<1)+(tp%2);
        tt[p]=a[i];
    }
    for (int m=2;m<=len;m*=2){
        int half=m/2;
        fo(i,0,half-1){
            node wi;
            wi.x=cos(i*pi*sig/half);wi.y=sin(i*pi*sig/half);
            for (int j=i;j<len;j+=m){
                node u=tt[j],v=tt[j+half]*wi;
                tt[j]=u+v;
                tt[j+half]=u-v;
            }
        }
    }
    if (sig==-1)
        fo(i,0,len-1) tt[i].x/=len;
    fo(i,0,len-1) a[i]=tt[i];
}
void FFT(node *a,node *b,node *c){
    int i;
    fo(i,0,len-1) e[i]=a[i],f[i]=b[i];
    DFT(e,1);DFT(f,1);
    fo(i,0,len-1) e[i]=e[i]*f[i];
    DFT(e,-1);
    fo(i,0,len-1) c[i]=e[i];
}
void calc(int f){
    int i;
    mx=0;
    fo(i,1,top)
        if (dep[a[i]]>mx) mx=dep[a[i]];
    len=1;
    while (len<=mx*2) len*=2;
    ce=log(len)/log(2);
    fo(i,0,len-1) d[i].x=0;
    fo(i,1,top) d[dep[a[i]]].x++;
    FFT(d,d,c);
    fo(i,0,len-1) cnt[i]+=f*round(c[i].x);
}
void solve(int x,int y){
    top=0;
    travel(x,0);
    if (y) calc(-1);
    int i,j=x,k=0,t;
    while (1){
        t=h[j];
        while (t){
            if (!bz[go[t]]&&go[t]!=k&&size[go[t]]>top/2){
                k=j;
                j=go[t];
                break;
            }
            t=next[t];
        }
        if (!t) break;
    }
    dep[j]=0;
    dfs(j,0);
    calc(1);
    bz[j]=1;
    t=h[j];
    while (t){
        if (!bz[go[t]]) solve(go[t],y+1);
        t=next[t];
    }
}
int main(){
    //freopen("3451.in","r",stdin);
    scanf("%d",&n);
    fo(i,1,n-1){
        scanf("%d%d",&j,&k);
        j++;k++;
        add(j,k);add(k,j);
    }
    solve(1,0);
    fo(i,0,n-1) ans+=(db)1/(i+1)*cnt[i];
    printf("%.4lf\n",ans);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值