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 ...
随机推荐
- 事务控制语言DTL
一.什么是事务? · 数据库中的事务,是指可以将“多条相关语句执行”看做是“一条语句执行”的一种内部机制.即事务是一种可以保证“多条语句一次性执行完成”或者一条语句都不执行的机制. 三.事务的特点 原 ...
- Cleaning Shifts POJ - 2376 (贪心题)
Cleaning Shifts Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 31194 Accepted: 7677 ...
- Linux交换分区swap
一.SWAP 说明 1.1 SWAP 概述 当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用.那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被 ...
- Kattis - doubleclique (图论)
From : North American Invitational Programming Contest 2018 给你一个图,以及它的补图.如果部分点在原图中是团,并且其他的所有点在补图中也是团 ...
- 带权并查集:CF-2015 ACM Arabella Collegiate Programming Contest(F题)
F. Palindrome Problem Description A string is palindrome if it can be read the same way in either di ...
- ACM 广度优化搜索算法总结
广度优化搜索算法的本质:要求每个状态不能重复,这就需要我们:第一次先走一步可以到达的状态,如果还没有找到答案,就需要我们走到两步可以到达的状态.依次下去 核心算法:队列 基本步骤: ...
- HBase0.94.2-cdh4.2.0需求评估测试报告1.0之二
Hbase 配置文件: hbase-site.xml <configuration> <property> <name>hbase.cluster.distribu ...
- Tarjan算法及其应用
Tarjan算法及其应用 引入 tarjan算法可以在图上求解LCA,强连通分量,双联通分量(点双,边双),割点,割边,等各种问题. 这里简单整理一下tarjan算法的几个应用. LCA http:/ ...
- HDU 5239 Doom 线段树
题意: 有\(n(1 \leq n \leq 10^5)\)个数,和\(m(1 \leq m \leq 10^5)\)操作,和一个计算\(s\),一切运算都在模\(MOD\)进行的. 操作\(l, \ ...
- Leetcode39--->Combination Sum(在数组中找出和为target的组合)
题目: 给定一个数组candidates和一个目标值target,求出数组中相加结果为target的数字组合: 举例: For example, given candidate set [2, 3, ...