zoukankan      html  css  js  c++  java
  • 【BZOJ3451】Normal (点分治)

    【BZOJ3451】Normal (点分治)

    题面

    BZOJ

    题解

    显然考虑每个点的贡献。但是发现似乎怎么算都不好计算其在点分树上的深度。
    那么考虑一下这个点在点分树中每一次被计算的情况,显然就是其在某个点的点分树内时才会被计算答案。
    那么设(p[i][j])表示(i)(j)的点分树里面的概率。
    那么答案就变成了(sum_isum_j p[i][j])
    那么(i)(j)的点分树的概率显然就是两点之间路径不被断开的概率,即(frac{1}{dis(i,j)+1})
    那么点分治+(FFT)统计即可。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    #define MAX 70000
    const double Pi=acos(-1);
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    struct Complex{double a,b;}A[MAX],B[MAX],W[MAX];
    Complex operator+(Complex a,Complex b){return (Complex){a.a+b.a,a.b+b.b};}
    Complex operator-(Complex a,Complex b){return (Complex){a.a-b.a,a.b-b.b};}
    Complex operator*(Complex a,Complex b){return (Complex){a.a*b.a-a.b*b.b,a.b*b.a+a.a*b.b};}
    int r[MAX];
    void FFT(Complex *P,int N,int opt)
    {
    	for(int i=0;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
    	for(int i=1;i<N;i<<=1)
    		for(int p=i<<1,j=0;j<N;j+=p)
    			for(int k=0;k<i;++k)
    			{
    				Complex w=W[N/i*k];w.b*=opt;
    				Complex X=P[j+k],Y=P[i+j+k]*w;
    				P[j+k]=X+Y;P[i+j+k]=X-Y;
    			}
    	if(opt==-1)for(int i=0;i<N;++i)P[i].a/=N;
    }
    struct Line{int v,next;}e[MAX<<1];
    int h[MAX],cnt=1;
    inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
    int size[MAX],rt,mx,Size;
    bool vis[MAX];
    void Getroot(int u,int ff)
    {
    	size[u]=1;int ret=0;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff||vis[v])continue;
    		Getroot(v,u);size[u]+=size[v];
    		ret=max(ret,size[v]);
    	}
    	ret=max(ret,Size-size[u]);
    	if(mx>ret)mx=ret,rt=u;
    }
    int Ans[MAX];
    int t[MAX],s[MAX],ln[MAX],md;
    void dfs(int u,int ff,int dep)
    {
    	t[dep]+=1;md=max(md,dep);
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff||vis[v])continue;
    		dfs(v,u,dep+1);
    	}
    }
    void Multi(int *a,int *b,int n,int m,int *c)
    {
    	int N,l=0;for(N=1;N<=n+m;N<<=1)++l;
    	for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	for(int i=1;i<N;i<<=1)
    		for(int k=0;k<i;++k)
    			W[N/i*k]=(Complex){cos(Pi/i*k),sin(Pi/i*k)};
    	for(int i=0;i<=n;++i)A[i].a=a[i];
    	for(int i=0;i<=m;++i)B[i].a=b[i];
    	FFT(A,N,1);FFT(B,N,1);
    	for(int i=0;i<N;++i)A[i]=A[i]*B[i];
    	FFT(A,N,-1);
    	for(int i=0;i<=n+m;++i)c[i]=A[i].a+0.5;
    	for(int i=0;i<N;++i)A[i]=B[i]=(Complex){0,0};
    }
    void Divide(int u)
    {
    	vis[u]=true;int mxd=0;
    	s[0]=1;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(vis[v])continue;
    		md=0;dfs(e[i].v,u,1);
    		Multi(s,t,mxd,md,ln);
    		for(int i=0;i<=mxd+md;++i)Ans[i]+=ln[i],ln[i]=0;
    		for(int i=0;i<=md;++i)s[i]+=t[i],t[i]=0;
    		mxd=max(mxd,md);
    	}
    	for(int i=0;i<=mxd;++i)s[i]=0;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(vis[v])continue;
    		Size=mx=size[v];Getroot(v,u);
    		Divide(rt);
    	}
    }
    int n;double ans;
    int main()
    {
    	n=read();
    	for(int i=1;i<n;++i)
    	{
    		int u=read()+1,v=read()+1;
    		Add(u,v);Add(v,u);
    	}
    	int N;for(N=1;N<=n;N<<=1);
    	for(int i=1;i<N;i<<=1)
    		for(int k=0;k<i;++k)
    			W[N/i*k]=(Complex){cos(Pi/i*k),sin(Pi/i*k)};
    	Size=mx=n;Getroot(1,0);Divide(rt);
    	for(int i=1;i<=n;++i)ans+=1.0*Ans[i]/(i+1);
    	ans*=2;ans+=n;
    	printf("%.4lf
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Firebird 用查询结果集更新数据,merge
    wcf 登录认证 angular 认证重定向
    WOSA/XFS PTR Form解析库—xfsptrdata.h
    WOSA/XFS PTR Form解析库—头文件
    2019,开启新征程
    VC中添加头文件以及库
    .net4.0多进程间共享内存实现通信(VB.Net)
    共享内存操作类(C#源码)
    VC++ 共享内存读写操作
    c#实现内存映射文件共享内存
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10391123.html
Copyright © 2011-2022 走看看