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 ...
随机推荐
- 20.Yii2.0框架多表关联一对多查询之hasMany
目录 新手模式 hasMany关联模式查询 新建mode层Article.php 新建mode层Category.php 新建控制器HomeController.php 新手模式 用上次的查询结果,作 ...
- Python基础——异常
捕捉所有异常 for i in range(10): try: input_number=input('write a number') if input_number=='q': break res ...
- debian 7 stable 不能编译android源码
rebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8-linaro/bin/arm-linux-androideabi-gcc: /lib/x86_ ...
- linux学习-systemd-journald.service 简介
过去只有 rsyslogd 的年代中,由于 rsyslogd 必须要开机完成并且执行了 rsyslogd 这个 daemon 之 后,登录文件才会开始记录.所以,核心还得要自己产生一个 klogd 的 ...
- UIAutomator输入中文
之前一直是英文的测试环境,包括手机也是英文的,app也是英文的,涉及不到中文输入法的东西.但现在在写中文的app,所以需要输入中文.看到网上的解决办法如下: 下载https://github.com/ ...
- joyoi tyvj1313 [NOIP2010初赛]烽火传递
单调队列优化dp #include <iostream> #include <cstdio> using namespace std; int dp[1000005], n, ...
- 再谈H2的MVStore与MVMap
对H2的[MVStore]: http://www.cnblogs.com/simoncook/p/5188105.html 这篇文章的补充. 概述 我们通常用的map,比如HashMap Linke ...
- rabbitmq exchange type
This is the fourth installment to the series: RabbitMQ for Windows. In thelast installment, we revi ...
- 【Go】Panic函数
panic(运行时恐慌)是一种只会在程序运行时才回抛出来的异常.在panic被抛出之后,如果没有在程序里添加任何保护措施的话,程序就会在打印出panic的详情,终止运行. 如果一个panic是无意间引 ...
- map/set/object/array对比
map () { //数据结构横向对比, 增,查,改,删 let map = new Map() let array = [] //增 map.set('t',1) array.push({t:1}) ...