luogu CF804D Expected diameter of a tree |Tarjan+樹的直徑+前綴和+二分查找

时间:2020-04-13
本文章向大家介绍luogu CF804D Expected diameter of a tree |Tarjan+樹的直徑+前綴和+二分查找,主要包括luogu CF804D Expected diameter of a tree |Tarjan+樹的直徑+前綴和+二分查找使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题意翻译

给一片森林,\(q\)个询问,每个询问两个点,问将这两个点所在的集合连接起来组成的新集合,它的最远两点的距离的期望值是多少。


調了2個小時,終於好啦

求出每個聯通快直徑的兩端點

預處理每個點到最遠的點的距離

排序,前綴和,快速計算

#include<map>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
#define int long long
#define db double
inline int read(){
	int x=0; char c=getchar();
	while(c<'0'||c>'9')c=getchar();
	while('0'<=c&&c<='9'){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); }
	return x;
}
int nxt[N<<1],head[N],go[N<<1],tot;
inline void add(int u,int v){
	nxt[++tot]=head[u],head[u]=tot,go[tot]=v;
	nxt[++tot]=head[v],head[v]=tot,go[tot]=u;
}
int n,m,q;
bool vis[N];
int dfn[N],low[N],co[N],st[N],si[N],top,col,num;
void Tarjan(int u){
	st[++top]=u;
	dfn[u]=low[u]=++num;
	for(int i=head[u];i;i=nxt[i]){
		int v=go[i];
		if(!dfn[v]){
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}else if(!co[v])
		low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){
		co[u]=++col;
		si[col]=1;
		while(st[top]!=u){
			co[st[top]]=col;
			si[col]++;
			--top;
		}	
		--top;
	}
}
int dis[N],all[N],coin[N],p,Max;
void dfs(int u,int fa){
	if(dis[u]>Max)Max=dis[u],p=u;
	all[u]=max(all[u],dis[u]);
	for(int i=head[u];i;i=nxt[i]){
		int v=go[i];
		if(v==fa)continue;
		dis[v]=dis[u]+1;
		dfs(v,u);
	}
}
inline void findp(int u){
	p=Max=-1; dfs(u,u); coin[co[u]]=max(coin[co[u]],Max);
	Max=-1; dis[p]=0; dfs(p,p); coin[co[u]]=max(coin[co[u]],Max);
	Max=-1; dis[p]=0; dfs(p,p); coin[co[u]]=max(coin[co[u]],Max);
}
vector<int>belong[N],Sum[N],e[N];
map<pair<int,int>,db>IF;
signed main(){
	n=read(),m=read(),q=read();
	for(int i=1;i<=m;i++)add(read(),read());
	for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
	for(int i=1;i<=n;i++){
		if(!vis[co[i]])findp(i),vis[co[i]]=1;
		belong[co[i]].push_back(i);
	}
	for(int i=1;i<=col;i++){
		for(int j=0;j<belong[i].size();j++)
		e[i].push_back(all[belong[i][j]]);
		sort(e[i].begin(),e[i].end());
		for(int j=0;j<belong[i].size();j++){
			Sum[i].push_back(e[i][j]);
			if(j)Sum[i][j]+=Sum[i][j-1];
		}
	}
	int x,y;
	while(q--){
		x=read(),y=read();
		int a=co[x],b=co[y];
		if(a==b){ printf("-1\n"); continue;}
		if(IF[make_pair(a,b)]>0)
		{ printf("%.9f\n",IF[make_pair(a,b)]); continue; }
		if(si[a]>si[b])swap(a,b);
		int ans=0,op=belong[a].size()*belong[b].size();
		int MAXN=max(coin[a],coin[b]);
		for(int i=0;i<e[a].size();i++){
			int A=e[a][i]+1;
			int mzx=upper_bound(e[b].begin(),e[b].end(),MAXN-A)-e[b].begin();
			ans+=MAXN*mzx;
			if(mzx==0)ans+=A*e[b].size()+Sum[b][Sum[b].size()-1];
			else ans+=A*(e[b].size()-mzx)+Sum[b][Sum[b].size()-1]-Sum[b][mzx-1];
		}
		db res=(db)ans/op;
		IF[make_pair(b,a)]=IF[make_pair(a,b)]=res;
		printf("%.10f\n",res);
	}
}

原文地址:https://www.cnblogs.com/naruto-mzx/p/12693052.html