Codeforces 804D Expected diameter of a tree
3 seconds
256 megabytes
standard input
standard output
Pasha is a good student and one of MoJaK's best friends. He always have a problem to think about. Today they had a talk about the following problem.
We have a forest (acyclic undirected graph) with n vertices and m edges. There are q queries we should answer. In each query two vertices v and u are given. Let V be the set of vertices in the connected component of the graph that contains v, and U be the set of vertices in the connected component of the graph that contains u. Let's add an edge between some vertex
and some vertex in
and compute the value d of the resulting component. If the resulting component is a tree, the value d is the diameter of the component, and it is equal to -1 otherwise. What is the expected value of d, if we choose vertices a and b from the sets uniformly at random?
Can you help Pasha to solve this problem?
The diameter of the component is the maximum distance among some pair of vertices in the component. The distance between two vertices is the minimum number of edges on some path between the two vertices.
Note that queries don't add edges to the initial forest.
The first line contains three integers n, m and q(1 ≤ n, m, q ≤ 105) — the number of vertices, the number of edges in the graph and the number of queries.
Each of the next m lines contains two integers ui and vi (1 ≤ ui, vi ≤ n), that means there is an edge between vertices ui and vi.
It is guaranteed that the given graph is a forest.
Each of the next q lines contains two integers ui and vi (1 ≤ ui, vi ≤ n) — the vertices given in the i-th query.
For each query print the expected value of d as described in the problem statement.
Your answer will be considered correct if its absolute or relative error does not exceed 10 - 6. Let's assume that your answer is a, and the jury's answer is b. The checker program will consider your answer correct, if
.
3 1 2
1 3
3 1
2 3
-1
2.0000000000
5 2 3
2 4
4 3
4 2
4 1
2 5
-1
2.6666666667
2.6666666667
In the first example the vertices 1 and 3 are in the same component, so the answer for the first query is -1. For the second query there are two options to add the edge: one option is to add the edge 1 - 2, the other one is 2 - 3. In both ways the resulting diameter is 2, so the answer is 2.
In the second example the answer for the first query is obviously -1. The answer for the second query is the average of three cases: for added edges 1 - 2 or 1 - 3 the diameter is 3, and for added edge 1 - 4 the diameter is 2. Thus, the answer is
.
题意:
给出一个森林,q次询问,每次问把x,y两点所属的树之间任意连接一条边形成新的树的直径的期望,如果x和y在同一棵树中输出-1;
代码:
//这题算出复杂度也就解出来了。先枚举一棵树中的节点然后二分找另一棵树中的节点满足两个节点之间的距离不小于max(树1直径,
//树2直径),他们的贡献就是各自在自己树中最远能到达的端点的距离相加再+1,否则贡献就是max(树1直径,树2直径),这样看似是
//q*n*long(n),但是注意到所有的树的大小总和是n所以最坏是sqrt(n)棵树每棵树大小是sqrt(n),所以是q*sqrt(n)*long(n);
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int MAXN=;
int fa[MAXN],head[MAXN],tot,n,cnt,m,q,d[MAXN],f[MAXN],deep,o,oo,root[MAXN];
int a[MAXN],aa;
double size[MAXN];
map<pair<int,int>,double>mp;
vector<ll>v[MAXN],vv[MAXN];
struct Edge { int u,v,next; }edge[MAXN*];
void init()
{
tot=cnt=;
memset(head,-,sizeof(head));
memset(fa,-,sizeof(fa));
memset(f,,sizeof(f));
memset(d,-,sizeof(d));
}
void add(int x,int y)
{
edge[tot].u=x;edge[tot].v=y;
edge[tot].next=head[x];
head[x]=tot++;
edge[tot].u=y;edge[tot].v=x;
edge[tot].next=head[y];
head[y]=tot++;
}
void dfs1(int x,int father,int p)
{
v[p].push_back(x);
for(int i=head[x];i!=-;i=edge[i].next){
int y=edge[i].v;
if(y==father) continue;
fa[y]=p;
dfs1(y,x,p);
}
}
void dfs2(int x,int father,int sum,bool w)
{
if(w!=) f[x]=max(f[x],sum);
if(sum>=deep){
deep=sum;
if(w==) o=x;
else if(w==) oo=x;
}
for(int i=head[x];i!=-;i=edge[i].next){
int y=edge[i].v;
if(y==father) continue;
dfs2(y,x,sum+,w);
}
}
int main()
{
//freopen("in.txt","r",stdin);
init();
scanf("%d%d%d",&n,&m,&q);
for(int i=;i<m;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=;i<=n;i++){
if(fa[i]!=-) continue;
fa[i]=++cnt;
v[cnt].clear();vv[cnt].clear();
dfs1(i,,cnt);
root[cnt]=i;
}
for(int i=;i<=cnt;i++){
deep=;
dfs2(root[i],,,);
deep=;
dfs2(o,,,);
d[i]=deep;
dfs2(oo,,,);
aa=v[i].size();
for(int j=;j<aa;j++) a[j]=f[v[i][j]];
v[i].clear();
for(int j=;j<aa;j++) v[i].push_back(a[j]);
sort(v[i].begin(),v[i].end());
a[aa]=;
for(int j=aa-;j>=;j--) a[j]=a[j+]+v[i][j]+;
for(int j=;j<=aa;j++) vv[i].push_back(a[j]);
}
while(q--){
int x,y;
scanf("%d%d",&x,&y);
if(fa[x]==fa[y]) printf("-1\n");
else{
pair<int,int>p1(fa[x],fa[y]);
if(mp[p1]>) printf("%.6f\n",mp[p1]);
else{
double ans=;
int xx=fa[x],yy=fa[y];
if(v[xx].size()<=v[yy].size()){
for(int i=;i<v[xx].size();i++){
ll tmp=lower_bound(v[yy].begin(),v[yy].end(),max(d[xx],d[yy])-v[xx][i]-)-v[yy].begin();
ans+=(vv[yy][tmp]+v[xx][i]*(v[yy].size()-tmp))+tmp*max(d[xx],d[yy]);
}
}else{
for(int i=;i<v[yy].size();i++){
ll tmp=lower_bound(v[xx].begin(),v[xx].end(),max(d[xx],d[yy])-v[yy][i]-)-v[xx].begin();
ans+=(vv[xx][tmp]+v[yy][i]*(v[xx].size()-tmp))+tmp*max(d[xx],d[yy]);
}
}
double tmp1=v[xx].size(),tmp2=v[yy].size();
ans/=(tmp1*tmp2);
printf("%.6f\n",ans);
mp[p1]=ans;
}
}
}
return ;
}
Codeforces 804D Expected diameter of a tree的更多相关文章
- Codeforces 804D Expected diameter of a tree(树的直径 + 二分 + map查询)
题目链接 Expected diameter of a tree 题目意思就是给出一片森林, 若把任意两棵树合并(合并方法为在两个树上各自任选一点然后连一条新的边) 求这棵新的树的树的直径的期望长度. ...
- Codeforces 804D Expected diameter of a tree(树形DP+期望)
[题目链接] http://codeforces.com/contest/804/problem/D [题目大意] 给你一个森林,每次询问给出u,v, 从u所在连通块中随机选出一个点与v所在连通块中随 ...
- Codeforces 840D Expected diameter of a tree 分块思想
Expected diameter of a tree 我们先两次dfs计算出每个点能到达最远点的距离. 暴力计算两棵树x, y连边直径的期望很好求, 我们假设SZ(x) < SZ(y) 我们枚 ...
- CodeForces 805F Expected diameter of a tree 期望
题意: 给出一个森林,有若干询问\(u, v\): 从\(u, v\)中所在子树中随机各选一个点连起来,构成一棵新树,求新树直径的期望. 分析: 回顾一下和树的直径有关的东西: 求树的直径 从树的任意 ...
- CF804D Expected diameter of a tree 树的直径 根号分治
LINK:Expected diameter of a tree 1e5 带根号log 竟然能跑过! 容易想到每次连接两个联通快 快速求出直径 其实是 \(max(D1,D2,f_x+f_y+1)\) ...
- Codeforces Round #411 (Div. 1) D. Expected diameter of a tree
题目大意:给出一个森林,每次询问给出u,v,问从u所在连通块中随机选出一个点与v所在连通块中随机选出一个点相连,连出的树的直径期望(不是树输出-1).(n,q<=10^5) 解法:预处理出各连通 ...
- codeforces804D Expected diameter of a tree
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 543. Diameter of Binary Tree
https://leetcode.com/problems/diameter-of-binary-tree/#/description Given a binary tree, you need to ...
- LeetCode 543. Diameter of Binary Tree (二叉树的直径)
Given a binary tree, you need to compute the length of the diameter of the tree. The diameter of a b ...
随机推荐
- n以内的1的个数
import java.util.Scanner; public class main { /** * @param args */ public static void main(String[] ...
- JAVA自学日记——Part Ⅰ.
和C++比较相似,Java同样是面向对象的设计语言,在基础的语句上有一些不大的差别,经过两天的学习,大概的了解了在eclipse中如何进行简单的编程,解决一些简单的问题,诸如在学习C时做过的“字符串倒 ...
- charles抓取移动端app数据
pc端为mac 移动端为android pc端 1.下载charles并安装 安利一个超好的良心网站(好多好用的软件都可以在上面找到,并且免费): http://xclient.info/search ...
- C++获取private的变量-偷走private
private提供了对数据的封装,使得private成员只能被类自身的成员函数以及类的友元访问,其他的函数或者类想要访问private成员只能通过该类所提供的set和get的方法进行访问, 或者返回其 ...
- 用go实现的一个堆得数据结构
用golang实现的堆,主要提供了两个方法,push和pop及堆的大小,代码如下: package main import ( "errors" "fmt" ) ...
- 一个flume agent异常的解决过程记录
今天在使用flume agent的时候,遇到了一个异常, 现把解决的过程记录如下: 问题的背景: 我使用flume agent 来接收从storm topology发送下来的accesslog , ...
- delphi(假三层之数据访问层)(第一天)
本论文主要是通过三天来讲解三层的结构,今天是第一天,先讲解一下delphi下的Models层,我主要封装了两个查询得到数据集的函数,主要是通过在表示层上创建的数数据集控件传递进来,通过业务逻辑对语句的 ...
- sqlserver查询数据库中包含某个字段的所有表和所有存储过程
1.查询包含某字段的所有表 select object_name(id) objName,Name as colName from syscolumns where (name like'%你要查询的 ...
- 子类使用父类的方法 或属性时候 里面的this 代表的是自己
- PGM学习之五 贝叶斯网络
本文的主题是“贝叶斯网络”(Bayesian Network) 贝叶斯网络是一个典型的图模型,它对感兴趣变量(variables of interest)及变量之间的关系(relationships) ...