2018 湖南省队集训模拟试题( 七)T2分岔路口 ( 二分求期望 + 点分治卡常数 )

130 篇文章 1 订阅
105 篇文章 0 订阅
题意 : n个点的树,两种操作1 : 走到相邻点。2 : 等概率传送到任意一点q次询问,问u到v在 最优策略 下的期望最少操作次数正解 :先贪心,最优策略一定是先不停传送直到抽中一个比较好的点然后直接走到终点,因为先走后传送没有意义,是浪费。那么我们一定可以找出一个点集S使得我们在S中的点时选择走路,反之传送。那么我们传送到S中的点的期望步数等于传送到S中的点的概率的相反数。n/|S|S的点走到...
摘要由CSDN通过智能技术生成

题意 : n个点的树,两种操作

1 : 走到相邻点。

2 : 等概率传送到任意一点

q次询问,问u到v在 最优策略 下的期望最少操作次数

正解 : 

先贪心,最优策略一定是先不停传送直到抽中一个比较好的点然后直接走到终点,因为先走后传送没有意义,是浪费。

那么我们一定可以找出一个点集S使得我们在S中的点时选择走路,反之传送。

那么我们传送到S中的点的期望步数等于传送到S中的点的概率的相反数。n/|S|

S的点走到终点的期望步数sigma(dis (i , tar)) / |S| (i∈S) (tar为终点)

总期望步数就是两个相加:

n/|S| +  sigma(dis (i , tar)) / |S| (i∈S)  >= K

 n + sigma(dis (i ,tar)) - K * |S| = 0

n + sigma(dis(i , tar) - K) = 0

sigma( K - dis(i , tar)) = n

可以发现S中的点一定满足dis(i,tar)<= K +1,满足此条件也必定在S中。

故|S|随K单不降,显然sigma( K - dis(i , tar))随K单不降,二分答案K再通过上述不等式求S,求sigma(K-dis(i,tar))与n的大小关系。

可以O(nlogn)求出K

但是终点有多个,于是想到利用树的性质,重复利用已算出的答案(sigma(dis(i,tar)))

求距离和,当然用点分治啦,不过是二分套点分治(常数巨大),开始卡常。

1 : 二分K时用整数二分,实数二分的话二分50次精度都不够,整数只需17次(想一想一次点分治的耗时),剩下的小数部分不会影响S,可以解一次方程(我要是出题人我就把可接受误差降到1e-12)

2 : 疯狂用空间换时间,不是有多次点分治吗 ?把相同的全部存起来,二分找dis(i,tar)<= K +1时不要用lower_bound,

手写二分,记得加inline(实测速度是lower_bound的1/2,实测优化之前一次点分治2000ms,火力全开优化后270ms)

3 : namespace是个好东西,妈妈再也不会担心我变量重名了。(我保守估计开了20个数组)

4 : 虽然原题时限4s,但是机房机子烂,标程都TLE了,可以适当放低要求。

5  : 这是我人生中第一个代码过350行的程序!!!!!

AC code:

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<vector>
#define LL long long
#include<set>
#define eps (1e-9)
#define maxn 100005
using namespace std;

int n,q;
double f[maxn];
int info[maxn],Prev[maxn*2],to[maxn*2],cnt_e;
inline void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }

int DIS[maxn*30],SUM[maxn*30],DIS2[maxn*30],SUM2[maxn*30],siz1,siz2;
int TOT[maxn],TOT2[maxn*30],siz3;
int dep[maxn],fa[maxn],son[maxn],siz[maxn],tp[maxn];

inline void dfs1(int now,int ff)
{
	dep[now]=dep[fa[now]=ff]+1;
	siz[now]=1;
	son[now]=-1;
	for(int i=info[now];i;i=Prev[i])
		if(to[i]!=ff)
		{
			dfs1(to[i],now);
			siz[now]+=siz[to[i]];
			if(son[now]==-1 || siz[to[i]] > siz[son[now]])son[now]=to[i];
		}
}

inline void dfs2(int now,int ff)
{
	if(son[now]!=-1) tp[son[now]]=tp[now],dfs2(son[now],now);
	for(int i=info[now];i;i=Prev[i])
		if(to[i]!=ff && to[i]!=son[now])
			tp[to[i]]=to[i],dfs2(to[i],now);
}

inline int Lca(int a,int b)
{
	for(;tp[a]!=tp[b];)
	{
		if(dep[tp[a]]<dep[tp[b]]) swap(a,b);
		a=fa[tp[a]];
	}
	if(dep[a]<dep[b]) return a;
	return b;
}

inline int dist(int u,int v){ return dep[u]+dep[v] - 2 * dep[Lca(u,v)]; }
/*
int seq[maxn];
double sum[maxn];
double solve(int v)
{
	double L=0,R=n,Mid;
	for(int i=1;i<=n;i++)
		seq[i]=dist(i,v);
	sort(seq+1,seq+1+n);
	for(int i=1;i<=n;i++)
		sum[i]=sum[i-1]+seq[i];
	for(;(R-L)>=eps;)
	{
		Mid=(L+R)*0.5;
		int u=upper_bound(seq+1,seq+1+n,Mid)-seq-1;
		if(sum[u]+1.0 * (n-u) * Mid<=(Mid-1)*n) //I wanna make some changes
			R=Mid;
		else 
			L=Mid+eps;
	}
	return L;
}
*/

LL L[maxn],R[maxn],Mid[maxn],had[maxn];

int Maxdep;
int rela[maxn];

namespace DFZ
{
	bool vis[maxn];
	int dfseq[maxn];
	int Min,rt;
	
	void Sert(int now ,int ff,int tsz)
	{
		int Max=0;
		siz[now]=1;
		for(int i=info[now];i;i=Prev[i])
			if(to[i]!=ff && !vis[to[i]])
			{
				Sert(to[i],now,tsz);
				Max=max(Max,siz[to[i]]);
				siz[now]+=siz[to[i]];
			}
		Max=max(Max,tsz-siz[now]);
		if(Max<Min || rt==-1)
			Min=Max,rt=now;
	}

	int Gert(int now,int tsz)
	{
		Min=0x3f3f3f3f,rt=-1;
		Sert(now,-1,tsz);
		return rt;
	}
	
	int dis[maxn],tot;
	double sum[maxn];
	void dfs(int now,int ff,int dist)
	{
		dis[++tot]=dist;
		for(int i=info[now];i;i=Prev[i])
			if(to[i]!=ff && !vis[to[i]])
				dfs(to[i],now,dist+1);
	}
	
	int dis2[maxn],tot2;
	double sum2[maxn];
	void ser(int now,int ff,int dist)
	{
		dis2[++tot2]=dist;
		for(int i=info[now];i;i=Prev[i])
			if(to[i]!=ff && !vis[to[i]])
				ser(to[i],now,dist+1);
	}
	
	int LLL=1,RR,mid;
	inline int sc1(double num)
	{
		LLL=1,RR=tot+1;
		while(LLL<RR)
		{
			mid=(LLL+RR)>>1;
			if(dis[mid]<=num) LLL=mid+1;
			else RR=mid;
		}
		return LLL;
	}
	
	inline int sc2(double num)
	{
		LLL=1,RR=tot2+1;
		while(LLL<RR)
		{
			mid=(LLL+RR)>>1;
			if(dis2[mid]<=num) LLL =mid+1;
			else RR=mid;
		}
		return LLL;
	}
	
	void solu(int now,int ff,int dist)
	{
		int u=sc1(Mid[now]-dist)-1,u2=sc2(Mid[now]-dist)-1;
		had[now]+=sum[u]+1.0 * dist * (u-u2)+1.0 * (tot-u-tot2+u2) * Mid[now]-sum2[u2];
		
		for(int i=info[now];i;i=Prev[i])
			if(to[i]!=ff && !vis[to[i]])
				solu(to[i],now,dist+1);
	}

	int us1=1,us2=1,us3=1;
	void solve(int num)
	{
		int now=dfseq[num];
		vis[now]=1;
		
		/*
		tot=0;
		dfs(now,0,0);
		sort(dis+1,dis+1+tot);
		for(int i=1;i<=tot;i++) sum[i]=sum[i-1]+dis[i];
		*/
		
		tot=TOT[now];
		for(int i=1;i<=tot;i++) 
		{
			dis[i]=DIS[us1];
			sum[i]=SUM[us1++];
		}
		
		int u=sc1(Mid[now])-1;
		had[now]+=sum[u]+1.0 * (tot-u) * Mid[now];
		
		for(int i=info[now];i;i=Prev[i])
		if(!vis[to[i]])
		{
			/*
			tot2=0;
			ser(to[i],now,1);
			siz[to[i]]=tot2;
			sort(dis2+1,dis2+1+tot2);
			for(int j=1;j<=tot2;j++) sum2[j]=sum2[j-1]+dis2[j];
			*/
			
			siz[to[i]]=tot2=TOT2[us3++];
			for(int j=1;j<=tot2;j++)
			{
				dis2[j]=DIS2[us2];
				sum2[j]=SUM2[us2++];
			}
			
			solu(to[i],now,1);
		}
		
		if(num%10==1)
			for(int i=1;i<=10 && i+num<=n;i++)
				solve(i+num);
	}
	
	int cnt_num=0;
	void Prepare(int now)
	{
		dfseq[++cnt_num]=now;
		vis[now]=1;
		
		tot=0;
		dfs(now,0,0);
		sort(dis+1,dis+1+tot);
		for(int i=1;i<=tot;i++)
		{
			sum[i]=sum[i-1]+dis[i];
			DIS[++siz1]=dis[i];
			SUM[siz1]=sum[i];
		}
		TOT[now]=tot;
		
		for(int i=info[now];i;i=Prev[i])
		if(!vis[to[i]])
		{
			tot2=0;
			ser(to[i],now,1);
			siz[to[i]]=tot2;
			sort(dis2+1,dis2+1+tot2);
			for(int j=1;j<=tot2;j++) 
			{
				sum2[j]=sum2[j-1]+dis2[j];
				DIS2[++siz2]=dis2[j];
				SUM2[siz2]=sum2[j];
			}
			
			TOT2[++siz3]=tot2;
		}
				
		for(int i=info[now];i;i=Prev[i])
			if(!vis[to[i]])
			{
				Prepare(Gert(to[i],siz[to[i]]));
			}
	}
	
	void solu2(int now,int ff,int dist)
	{
		rela[now]+=tot-sc1(L[now]-dist) - tot2 + sc2(L[now]-dist);
		
		for(int i=info[now];i;i=Prev[i])
			if(to[i]!=ff && !vis[to[i]])
				solu2(to[i],now,dist+1);
	}
	
	void solve2(int num)
	{
		int now=dfseq[num];
		vis[now]=1;
		tot=TOT[now];
		for(int i=1;i<=tot;i++) 
		{
			dis[i]=DIS[us1];
			sum[i]=SUM[us1++];
		}
		
		rela[now]+=tot-sc1(L[now])+1;
		
		for(int i=info[now];i;i=Prev[i])
		if(!vis[to[i]])
		{
			/*
			tot2=0;
			ser(to[i],now,1);
			siz[to[i]]=tot2;
			sort(dis2+1,dis2+1+tot2);
			for(int j=1;j<=tot2;j++) sum2[j]=sum2[j-1]+dis2[j];
			*/
			
			siz[to[i]]=tot2=TOT2[us3++];
			for(int j=1;j<=tot2;j++)
			{
				dis2[j]=DIS2[us2];
				sum2[j]=SUM2[us2++];
			}
			
			solu2(to[i],now,1);
		}
		
		if(num%10==1)
			for(int i=1;i<=10 && i+num<=n;i++)
				solve2(i+num);
	}
}
double ans[maxn];
	
inline void read(int &res)
{
	char ch;
	for(;!isdigit(ch=getchar()););
	for(res=ch-'0';isdigit(ch=getchar());res=res*10+ch-'0');
}

int main()
{
	freopen("branching.in", "r",stdin);
	freopen("branching.out","w",stdout);
	
	read(n),read(q);
	for(int i=1,u,v;i<n;i++)
	{
		read(u),read(v);
		Node(u,v),Node(v,u);
	}
	
	dfs1(1,0);
	tp[1]=1;
	dfs2(1,0);
	
	DFZ::Prepare(DFZ::Gert(1,n));
	
	for(int i=1;i<=n;i++) L[i]=0,R[i]=n;
	for(int i=1;i<=17;i++)
	{
		for(int i=1;i<=n;i++) 
			Mid[i]=int((L[i]+R[i]) * 0.5), had[i]=DFZ::vis[i]=0;
			
		
		DFZ::us1=DFZ::us2=DFZ::us3=1;
		DFZ::solve(1);
		
		for(int i=1;i<=n;i++)
			if(had[i]<=(Mid[i]-1) * n) R[i]=Mid[i];
			else L[i]=Mid[i];
		
	}
	
	DFZ::us1=DFZ::us2=DFZ::us3=1;
	memset(DFZ::vis,0,sizeof DFZ::vis);
	DFZ::solve2(1);
	for(int i=1;i<=n;i++)
	{
		had[i]-=rela[i] * Mid[i];
		ans[i] = 1.0 * ( n + had[i] ) / (n - rela[i]);
	}
	
	for(int u,v;q--;)
	{
		read(u),read(v);
		printf("%.8lf\n",min(1.0 * dist(u,v) , ans[v]));
	}
	
}

UPD:退役前莫名又打了一遍,也不算特别长吧。

 

#include<bits/stdc++.h>
#define maxn 200005
#define LL long long
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;

char cb[1<<16],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<16,stdin),cs==ct)?0:*cs++)
void read(int &res){
	char ch;bool f=0;
	for(;!isdigit(ch=getc());) if(ch=='-') f= 1;
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
	(f) && (res=-res);
}


#define lim 18
int n,q;
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }

int vis[maxn],sz[maxn],dp[maxn],ds[lim+1][maxn];
void dfs0(int u,int ff,int tsz,int &mn,int &rt){
	int mx = 0;sz[u] = 1;
	for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff && !vis[v]){
		dfs0(v,u,tsz,mn,rt);
		mx = max(mx , sz[v]); 
		sz[u] += sz[v];
	}
	if((mx=max(mx,tsz-sz[u])) < mn)
		mn = mx , rt = u;
} 

int Gert(int u,int tsz){
	int mn = 0x3f3f3f3f , rt = -1;
	dfs0(u,0,tsz,mn,rt);
	return rt;
}

vector<int>psz[maxn],fsz[maxn];
vector<LL>psm[maxn],fsm[maxn];

void dfs1(int u,int ff,int d,vector<int>&psz,vector<LL>&psm){
	while(d >= psz.size()) psz.push_back(0);
	while(d >= psm.size()) psm.push_back(0);
	psz[d] ++ , psm[d] += d;sz[u] = 1;
	for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff && !vis[v])
		dfs1(v,u,d+1,psz,psm) , sz[u] += sz[v]; 
}

void dfs3(int u,int ff,int d,int *ds){
	ds[u] = d;
	for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff && !vis[v])
		dfs3(v,u,d+1,ds);
}

int fa[maxn];
void Build(int u,int d){
	vis[u] = 1 , dp[u] = d;
	dfs1(u,0,0,psz[u],psm[u]);
	dfs3(u,0,0,ds[d]);
	rep(i,1,psz[u].size()-1)
		psz[u][i] += psz[u][i-1],
		psm[u][i] += psm[u][i-1];
	for(int i=info[u],v;i;i=Prev[i]) if(!vis[v=to[i]]){
		int t = Gert(v,sz[v]);
		fa[t] = u;
		dfs1(v,0,1,fsz[t],fsm[t]);
		rep(j,1,fsz[t].size()-1)
			fsz[t][j] += fsz[t][j-1],
			fsm[t][j] += fsm[t][j-1];
		Build(t,d+1);
	}
}

pair<int,LL> qry(int p,int x){// leq x
	pair<int,LL>ret = make_pair(0,0);
	int u = p , pr = 0;
	for(;p;p=fa[pr = p]) if(x - ds[dp[p]][u] >= 0){
		int t = x - ds[dp[p]][u];
		ret.first += psz[p][min((int)psz[p].size()-1 , t)];
		ret.second += psm[p][min((int)psm[p].size()-1 , t)] + 1ll * psz[p][min((int)psz[p].size()-1 , t)] * ds[dp[p]][u];
	//	printf("@%d %lld\n",p,ret.second);
		
		if(pr)
			ret.first -= fsz[pr][min((int)fsz[pr].size()-1 , t)],	
			ret.second -= fsm[pr][min((int)fsm[pr].size()-1 , t)] + 1ll * fsz[pr][min((int)fsz[pr].size()-1 , t)] * ds[dp[p]][u];
	//	printf("@%d %lld\n",p,ret.second);
	}		
	return ret;
}
int f[lim][maxn],dep[maxn];
void dfs2(int u,int ff){
	dep[u] = dep[f[0][u] = ff] + 1;
	for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff)
		dfs2(v,u);
}

int Lca(int u,int v){
	if(dep[u] < dep[v]) swap(u,v);
	for(int i=0;dep[u] > dep[v];i++) 
		if(dep[u] - dep[v] >> i & 1)
			u  = f[i][u];
	if(u == v) return u;
	for(int i=lim-1;i>=0;i--) 
		if(f[i][u] != f[i][v])
			u = f[i][u] , v = f[i][v];
	return f[0][u];
}

int main(){
	freopen("branching.in","r",stdin);
	freopen("branching.out","w",stdout);
	
	read(n),read(q);
	rep(i,1,n-1){
		int x,y;
		read(x),read(y);
		Node(x,y),Node(y,x);
	}
	Build(Gert(1,n),1);
	dfs2(1,0);
	rep(j,1,lim-1) rep(i,1,n) f[j][i] = f[j-1][f[j-1][i]];
	for(int x,y;q--;){
		read(x),read(y);
		int L = 0 , R = n , mid;
		while(L<R){
		 	mid = L+R+1>>1;
		 	pair<int,LL> t = qry(y,mid);
		 	//eq : t.second + (n - t.first) * (g+1) = ng
			 double g = (t.second + n - t.first * 1.0) / t.first;
			// printf("%d %d %lld %.8lf\n",mid,t.first,t.second,g);
			if(g + 1 < mid) R = mid - 1;
			else L = mid; 
		}
		pair<int,LL> t = qry(y,L);
		double g = (t.second + n - t.first * 1.0) / t.first;
		printf("%.8lf\n",min(g+1,dep[x] + dep[y] - 2.0 * dep[Lca(x,y)]));
	}
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值