Codeforces 804D Expected diameter of a tree(树的直径 + 二分 + map查询)
题目链接 Expected diameter of a tree
题目意思就是给出一片森林,
若把任意两棵树合并(合并方法为在两个树上各自任选一点然后连一条新的边)
求这棵新的树的树的直径的期望长度。
我们对每棵独立的树,对于这棵树的每一个点$u$,求出$f[u]$
$f[u]$为这棵树上离$u$最远的点到$u$的距离。
同时我们求出每棵树上的树的直径的长度
现在合并两棵树$A$和$B$的时候,合成的新的树的直径$C$其实有三种情况。
对$A$树中的某点$x$,$B$树中的某点$y$
1、可能是$A$树中树的直径,长度为$d[A]$
2、可能是$B$树中树的直径,长度为$d[B]$
3、可能是:离$A$树中点$x$最远的点$-->x-->y-->$离$B$树中点$y$最远的点
长度为$f[x] + f[y] + 1$
三种情求最大值即可
在枚举所有情况的时候,对每个点x枚举y
我们要求的是$max(f[x] + f[y] + 1, d[A], d[B])$
其中令$max(d[A], d[B]) = Z$
那么我们要求的就是$max(f[x] + f[y] + 1, Z)$
我们两两枚举$x$和$y$显然是要超时的,怎么优化呢?
我们可以在两棵树中选一棵规模较小的树,枚举这棵树上的每个点$x$
对于另一棵树$B$,二分一个临界值,在这个临界值两边
我分别取较大的$f[x] + f[y] + 1$ 或是 $Z$
这道题数据规模比较大,询问的时候的给出两个点,一个点在$A$树上,一个点在$B$树上
所以他如果不友好一点,在某两棵点很多的树上选很多不同的点对来构成很多次询问。
但事实上他们的本质是同一个询问,这个时候还是有可能超时。
那么我们就把每棵独立的树编号,每次处理完一个询问,把答案塞到map里面
那么下一次处理到本质相同的询问的时候,就可以直接拿出来了。
(这道题真的很锻炼代码能力,当初做的时候调了好几个小时……)

#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = ; int n, m, q, L, R, nowdep, treenum = ;
int father[N], tr[N], c[N], f[N], d_max[N];
vector <int> v[N], tree[N], dis[N], g[N]; set < int > st;
map < int, int > mp;
map < pair<int, int> , double > ans;
map < pair<int, int> , int > flag; int getfather(int x){
return father[x] ? father[x] = getfather(father[x]) : x;
} void dfs(int x, int fa, int dep){
f[x] = max(f[x], dep);
for (auto u : v[x]){
if (u == fa) continue;
dfs(u, x, dep + );
}
} void dfs1(int x, int fa, int dep){
if (dep > nowdep){
L = x;
nowdep = dep;
} for (auto u : v[x]){
if (u == fa) continue;
dfs1(u, x, dep + );
}
} void dfs2(int x, int fa, int dep){
if (dep > nowdep){
R = x;
nowdep = dep;
} for (auto u : v[x]){
if (u == fa) continue;
dfs2(u, x, dep + );
}
} int main(){ scanf("%d%d%d", &n, &m, &q);
memset(father, , sizeof father);
rep(i, , m){
int x, y;
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
int fa = getfather(x), fb = getfather(y);
if (fa != fb) father[fa] = fb;
} rep(i, , n) st.insert(getfather(i)); for (auto u : st){
mp[u] = ++treenum;
tr[treenum] = u;
} rep(i, , n){
int x = getfather(i);
tree[mp[x]].push_back(i);
c[i] = mp[x];
} memset(f, , sizeof f); rep(i, , treenum){
L = ; nowdep = -;
dfs1(tree[i][], , );
R = , nowdep = -;
dfs2(L, , );
dfs(L, , );
dfs(R, , );
for (auto u : tree[i]) dis[i].push_back(f[u]);
sort(dis[i].begin(), dis[i].end());
rep(j, , (int)tree[i].size() - ){
if (j == ) g[i].push_back(dis[i][j]);
else g[i].push_back(g[i][j - ] + dis[i][j]);
}
d_max[i] = dis[i][(int)tree[i].size() - ];
} ans.clear();
flag.clear(); for (; q--; ){
int x, y;
scanf("%d%d", &x, &y);
if (c[x] == c[y]){
puts("-1");
continue;
}
int na = c[x], nb = c[y];
if ((int) tree[na].size() > (int) tree[nb].size()) swap(na, nb);
if (flag[{na, nb}]){
printf("%.12f\n", ans[{na, nb}]);
continue;
} LL X = ;
LL Y = (LL) tree[na].size() * tree[nb].size();
LL Z = max(d_max[na], d_max[nb]);
for (auto u1 : tree[na]){
LL A = lower_bound(dis[nb].begin(), dis[nb].end(), Z - - f[u1]) - dis[nb].begin();
X += (LL) A * Z +
(LL) (g[nb][(int)tree[nb].size() - ] + (int)tree[nb].size() - A - (A ? g[nb][A - ] : )) +
(f[u1]) * ((LL) tree[nb].size() - A);
} double cnt_ans = (double) X / (double) Y;
printf("%.12f\n", cnt_ans); flag[{na, nb}] = ;
ans[{na, nb}] = cnt_ans;
} return ;
}
Codeforces 804D Expected diameter of a tree(树的直径 + 二分 + map查询)的更多相关文章
- Codeforces 804D Expected diameter of a tree
D. Expected diameter of a tree time limit per test 3 seconds memory limit per test 256 megabytes inp ...
- CF804D Expected diameter of a tree 树的直径 根号分治
LINK:Expected diameter of a tree 1e5 带根号log 竟然能跑过! 容易想到每次连接两个联通快 快速求出直径 其实是 \(max(D1,D2,f_x+f_y+1)\) ...
- 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\)中所在子树中随机各选一个点连起来,构成一棵新树,求新树直径的期望. 分析: 回顾一下和树的直径有关的东西: 求树的直径 从树的任意 ...
- Codeforces Round #411 (Div. 1) D. Expected diameter of a tree
题目大意:给出一个森林,每次询问给出u,v,问从u所在连通块中随机选出一个点与v所在连通块中随机选出一个点相连,连出的树的直径期望(不是树输出-1).(n,q<=10^5) 解法:预处理出各连通 ...
- Codeforces Round #379 (Div. 2) E. Anton and Tree 树的直径
E. Anton and Tree time limit per test 3 seconds memory limit per test 256 megabytes input standard i ...
- codeforces804D Expected diameter of a tree
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- codeforces GYM 100114 J. Computer Network tarjan 树的直径 缩点
J. Computer Network Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Des ...
随机推荐
- yield关键字有什么作用
所属网站分类: python基础 > 语句 作者:goodbody 链接: http://www.pythonheidong.com/blog/article/10/ 来源:python黑洞网 ...
- tuple 方法总结整理
#!/usr/bin/env python #Python 3.7.0 元祖常用方法 __author__ = "lrtao2010" #元祖和列表类似,只不过元祖一旦被创建一级元 ...
- 通过IAR工程文件查看对应IAR版本号
IAR使用技巧——如何使用合适的版本打开IAR工程 2014年07月05日 23:49:08 xukai871105 阅读数:12895 标签: IAR 更多 个人分类: 嵌入式ARM 0.前言 ...
- hdu-2063 过山车(二分图)
Time limit1000 ms Memory limit32768 kB RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了.可是,过山车的每一排只有两个座位,而且还有条不 ...
- hdu 3836 tarjain 求强连通分量个数
// 给你一个有向图,问你最少加几条边能使得该图强连通 #include <iostream> #include <cstdio> #include <cstring&g ...
- poj 1862 2*根号(n1*n2)问题 贪心算法
题意: 有n个数,要把其中2个数进行2*根号(n1*n2)操作,求剩下最小的那个数是多少? 哭诉:看题目根本没看出来要让我做这个操作. 思路: 每次把最大的,次大的拿出来进行操作 用"优先队 ...
- HDU 3861 The King’s Problem 强连通分量 最小路径覆盖
先找出强连通分量缩点,然后就是最小路径覆盖. 构造一个二分图,把每个点\(i\)拆成两个点\(X_i,Y_i\). 对于原图中的边\(u \to v\),在二分图添加一条边\(X_u \to Y_v\ ...
- UOJ 152 汉诺塔 分治
题目链接 题意: 有三根编号为\((1, \, 2, \, 3)\)的柱子,然后第一根柱子上有编号为\(1 \sim n(n \leq 10000)\)的盘子,从上到下第\(i\)个盘子的编号是\(A ...
- curl download zip file
https://askubuntu.com/questions/285976/download-zip-file-with-curl-command
- zuul session 不一致的问题
配置文件: #不加这句话导致session不一致zuul.routes.intelligentsia-authority.sensitiveHeaders = Authorization 过滤器里面 ...