Codeforces 804D Expected diameter of a tree(树的直径)
来源:互联网 发布:淘宝卖家手机号采集 编辑:程序博客网 时间:2024/06/03 17:45
F. Expected diameter of a tree
time limit per test3 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard 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.
Input
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.
Output
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 .
Examples
input
3 1 2
1 3
3 1
2 3
output
-1
2.0000000000
input
5 2 3
2 4
4 3
4 2
4 1
2 5
output
-1
2.6666666667
2.6666666667
Note
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 .
题目大意
有一个
解题思路
首先判定输入两个点是否在一棵树上,非常简单,用并查集即可。
考虑两棵树连接的时候直径的变化,实际上只有两种情况。第一种情况是新的直径是两棵树直径的最大值,第二种情况是两个连接点在原树中的最远距离之和加一。两者最大值即为新的直径。
那么对于一次查询,我们可以先枚举点少的一棵树上的各个点,然后就可以在另一棵树的每一个点最远距离中二分找到新直径是两者最大值的点数,这样就可以直接算出这些点的贡献,其它的点可以利用前缀和
求树的直径可以用树形DP或从任意一个点DFS,再从最远的点DFS,最远的距离就是直径。树上任意一个点距离最远的点一定是直径的端点之一,所以我们可以从任意点DFS一遍,再从最远点DFS一遍,再从最远点DFS一遍得到所有需要的信息。
每次查询的时间复杂度为
AC代码
#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <vector>#include <queue>#include <stack>#include <cmath>#include <cstdlib>#include <string>#include <map>#include <set>using namespace std;#define INF 0x3f3f3f3f#define LL long long#define fi first#define se second#define mem(a,b) memset((a),(b),sizeof(a))#define sqr(x) ((x)*(x))const int MAXN=100000+3;int V, E, Q;vector<int> G[MAXN];int par[MAXN], high[MAXN];int d[MAXN];//直径vector<int> max_dis[MAXN];//每个点到树上其它点的最大距离vector<LL> sum[MAXN];//max_dis的前缀和int the_max, ind, dis[MAXN];map<pair<int, int>, double> save_ans;//保存答案,遇到相同的询问直接输出int findfather(int x){ return par[x]=par[x]==x?x:findfather(par[x]);}bool unite(int a, int b){ int fa=findfather(a), fb=findfather(b); if(fa==fb) return false; if(high[fa]>high[fb]) par[fb]=fa; else { par[fa]=fb; if(high[fa]==high[fb]) ++high[fb]; } return true;}void init(){ for(int i=1;i<=V;++i) par[i]=i;}void dfs1(int u, int fa, int d)//找最远的点,同时得到每个点到起点低距离{ dis[u]=d; if(d>the_max) { the_max=d; ind=u; } for(int i=0;i<G[u].size();++i) { int v=G[u][i]; if(v==fa) continue; dfs1(v, u, d+1); }}void dfs2(int u, int fa, int d, int root)//得到每个点到其它点的最大距离{ dis[u]=max(dis[u], d); max_dis[root].push_back(dis[u]); for(int i=0;i<G[u].size();++i) { int v=G[u][i]; if(v==fa) continue; dfs2(v, u, d+1, root); }}void pre_work(int u)//对于u所在的树预处理{ the_max=0; ind=u; dfs1(u, -1, 0); the_max=0; dfs1(ind, -1, 0); d[u]=the_max; dfs2(ind, -1, 0, u); sort(max_dis[u].begin(), max_dis[u].end()); sum[u].push_back(max_dis[u][0]); for(int i=1;i<max_dis[u].size();++i) sum[u].push_back(sum[u][i-1]+max_dis[u][i]);}int main(){ scanf("%d%d%d", &V, &E, &Q); init(); for(int i=0;i<E;++i) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); unite(u, v); } for(int i=1;i<=V;++i) if(i==findfather(i)) pre_work(i); while(Q--) { int u, v; scanf("%d%d", &u, &v); u=findfather(u); v=findfather(v); if(u==v) { puts("-1"); continue; } if(max_dis[u].size()>max_dis[v].size()) swap(u, v); if(save_ans.find(make_pair(u, v))!=save_ans.end()) { printf("%.10f\n", save_ans[make_pair(u, v)]); continue; } int org_d=max(d[u], d[v]); double ans=0; for(int i=0;i<max_dis[u].size();++i) { LL num=upper_bound(max_dis[v].begin(), max_dis[v].end(), org_d-max_dis[u][i]-1)-max_dis[v].begin(); ans+=num*org_d; if(num<max_dis[v].size()) ans+=(max_dis[v].size()-num)*(max_dis[u][i]+1)+sum[v].back()-(num?sum[v][num-1]:0); } ans/=max_dis[u].size()*max_dis[v].size(); save_ans[make_pair(u, v)]=ans; printf("%.10f\n", ans); } return 0;}
- Codeforces 804D Expected diameter of a tree(树的直径)
- [树的直径] Codeforces 804D Round #411 (Div. 1) D. Expected diameter of a tree
- Codeforces Round #411 (Div. 1) D. Expected diameter of a tree(树的直径)
- CF804D:Expected diameter of a tree(树的直径 & dfs)
- 543. Diameter of Binary Tree (二叉树的直径)
- codeforces805F Expected diameter of a tree
- 【二叉树】树的直径【543. Diameter of Binary Tree】
- 543. Diameter of Binary Tree 二叉树的直径
- 543. Diameter of Binary Tree | 二叉树的“直径”
- 543. Diameter of Binary Tree 二叉树的直径
- leetcode解题之543. Diameter of Binary Tree Java版 (二叉树的最大直径)
- Codeforces 337D Book of Evil (树的直径)
- [LeetCode]543. Diameter of Binary Tree(计算二叉树的直径的长度)
- 树直径、二叉树直径 Tree diameter (Longest path in an undirected tree)
- The diameter of a binary tree
- The diameter of a binary tree
- Codeforces-734E Anton and Tree(树的直径)
- Codeforces--14D--Two Paths(树的直径)
- 2017107网页使用ajax与程序通信
- Ubuntu 16.04 隐藏登录界面中的用户
- C++数值类型与string的相互转换
- 打印100~200 之间的素数
- HBuilder 常用快捷键
- Codeforces 804D Expected diameter of a tree(树的直径)
- Linux之Xampp外网访问不了
- mysql 中 all any some 用法
- 数据结构的概述
- 巧用插件及代码实现VIP视频源码分析观看(基于油猴插件及各大接口网站)【PC以及安卓】
- SpringBoot项目创建报:java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication错误的解决方案
- java中的匿名内部类总结
- 增长率问题
- chrom插件DHC和火狐HttpRequester插件教程