联考20200618 T2 分岔路口

题目:

分析:
神仙期望,神仙结论:
对于一个点,肯定先随机跳再一路走到终点,这样是最优的
一个点向终点走了之后再随机跳,不会比直接随机跳更优
一个点的期望只与他到终点的距离有关
我们想找到一个阈值\(D\),使得离终点小于等于\(D\)的点直接走最优
显然可以二分,可是如何判断?
我们算出距离大于\(mid\)的点随机跳到小于等于\(mid\)的点的期望步数,加上直接走的期望步数\(x\)
如果小于\(mid\)说明还要多进行随机跳,将\(mid\)缩小,否则增大
期望步数\(x\)实际上是距离和除以点数,这个需要动态点分治维护一下
复杂度\(O(nlog^{2}n)\)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>

#define maxn 400005
#define MOD 998244353
#define INF 0x3f3f3f3f

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,q;
int fir[maxn],nxt[maxn],to[maxn],cnt;
int f[18][maxn],dpt[maxn];
int Sz[maxn],Dpt[maxn],Fa[maxn],vis[maxn];

int dis[18][maxn];
vector<long long>sz[maxn],fsz[maxn],sum[maxn],fsum[maxn];

inline void newnode(int u,int v)
{to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void getsz(int u,int lst,int N,int &mn,int &rt)
{
	Sz[u]=1;int mx=0;
	for(int i=fir[u];i;i=nxt[i])if(!vis[to[i]]&&to[i]!=lst)
	{
		getsz(to[i],u,N,mn,rt),Sz[u]+=Sz[to[i]];
		mx=max(mx,Sz[to[i]]);
	}
	mx=max(mx,N-Sz[u]);
	if(mx<mn)mn=mx,rt=u;
}
inline int getrt(int u,int N)
{
	int mn=INF,rt;
	getsz(u,0,N,mn,rt);return rt;
}

inline void getp(int u,int lst,int d,vector<long long>&sz,vector<long long>&sum)
{
	while(d>=sz.size())sz.push_back(0);
	while(d>=sum.size())sum.push_back(0);
	sz[d]++,sum[d]+=d,Sz[u]=1;
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=lst&&!vis[to[i]])
		getp(to[i],u,d+1,sz,sum),Sz[u]+=Sz[to[i]]; 
}
inline void getdis(int u,int lst,int d,int id)
{
	dis[id][u]=d;
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=lst&&!vis[to[i]])
		getdis(to[i],u,d+1,id);
}

inline void solve(int u,int d)
{
	vis[u]=1,Dpt[u]=d;
	getp(u,0,0,sz[u],sum[u]);
	getdis(u,0,0,d);
	for(int i=1;i<sz[u].size();i++)
		sz[u][i]+=sz[u][i-1],sum[u][i]+=sum[u][i-1];
	for(int i=fir[u];i;i=nxt[i])if(!vis[to[i]])
	{
		int t=getrt(to[i],Sz[to[i]]);
		Fa[t]=u;
		getp(to[i],0,1,fsz[t],fsum[t]);
		for(int i=1;i<fsz[t].size();i++)
			fsz[t][i]+=fsz[t][i-1],fsum[t][i]+=fsum[t][i-1];
		solve(t,d+1);
	}
}

inline void dfs(int u)
{
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=f[0][u])
		f[0][to[i]]=u,dpt[to[i]]=dpt[u]+1,dfs(to[i]);
}
inline int LCA(int u,int v)
{
	if(dpt[u]<dpt[v])swap(u,v);
	for(int i=17;~i;i--)if((dpt[u]-dpt[v])&(1<<i))u=f[i][u];
	if(u==v)return u;
	for(int i=17;~i;i--)if(f[i][u]!=f[i][v])u=f[i][u],v=f[i][v];
	return f[0][u];
}

inline pair<long long,long long>query(int p,int x)
{
	long long ret1=0,ret2=0;
	int u=p,pr=0;
	while(p)
	{
		if(x-dis[Dpt[p]][u]>=0)
		{
			int t=x-dis[Dpt[p]][u];
			ret1+=sz[p][min((int)sz[p].size()-1,t)];
			ret2+=sum[p][min((int)sum[p].size()-1,t)]+sz[p][min((int)sz[p].size()-1,t)]*dis[Dpt[p]][u];
			if(pr)
			{
				ret1-=fsz[pr][min((int)fsz[pr].size()-1,t)];
				ret2-=fsum[pr][min((int)fsum[pr].size()-1,t)]+fsz[pr][min((int)fsz[pr].size()-1,t)]*dis[Dpt[p]][u];
			}
		}
		pr=p,p=Fa[p];
	}
	return make_pair(ret1,ret2);
}

int main()
{
	n=getint(),q=getint();
	for(int i=1;i<n;i++)
	{
		int u=getint(),v=getint();
		newnode(u,v),newnode(v,u);
	}
	solve(getrt(1,n),0);
	dfs(1);
	for(int j=1;j<18;j++)for(int i=1;i<=n;i++)f[j][i]=f[j-1][f[j-1][i]];
	while(q--)
	{
		int x=getint(),y=getint();
		int L=0,R=n,mid;
		while(L<R)
		{
			mid=(L+R+1)>>1;
			pair<long long,long long>t=query(y,mid);
			double g=1.0*(t.second+n-t.first)/t.first;
			if(g+1<mid)R=mid-1;
			else L=mid; 
		}
		pair<long long,long long>t=query(y,L);
		double g=1.0*(t.second+n-t.first)/t.first;
		printf("%.8lf\n",min(g+1,1.0*dpt[x]+dpt[y]-2*dpt[LCA(x,y)]));
	}
}

posted @ 2020-06-18 22:27  Izayoi_Doyo  阅读(261)  评论(0编辑  收藏  举报