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 ...
随机推荐
- Lecture 2
1. Coordinate(坐标) data for GIS real coordinate system:Cartesian coordinate systems(笛卡尔坐标系) from 3D t ...
- LeetCode(290) Word Pattern
题目 Given a pattern and a string str, find if str follows the same pattern. Here follow means a full ...
- luogu1501 [国家集训队]Tree II
lct裸题 #include <iostream> #include <cstdio> using namespace std; typedef long long ll; i ...
- 在从1到n的正数中1出现的次数 【微软面试100题 第三十题】
题目要求: 给定 一个十进制正整数N,写下从1开始,到N的所有整数,然后数一下其中出现的所有“1”的个数. 例如:N = 2,写下1,2.这样只出现了1个“1”. N = 12 ...
- Selenium WebDriver- 操作JavaScript的Alert弹窗
弹层和弹框是有区别的,弹框是那种完全没样式的框子:弹层是可以直接看到html的,有样式 #encoding=utf-8 import unittest import time from seleniu ...
- 30行js让你的rem弹性布局适配所有分辨率(含竖屏适配)
用rem来实现移动端的弹性布局是个好主意!用法如下: CSS @media only screen and (max-width: 320px), only screen and (max-devic ...
- C++程序在Windows平台上各种定位内存泄漏的方法,并对比了它们的优缺点
一.前言 在Linux平台上有valgrind可以非常方便的帮助我们定位内存泄漏,因为Linux在开发领域的使用场景大多是跑服务器,再加上它的开源属性,相对而言,处理问题容易形成“统一”的标准.而在W ...
- jQuery 样式操作、文档操作、属性操作的方法总结
文档操作: addClass() 向匹配的元素添加指定的类名.after() 在匹配的元素之后插入内容.append() ...
- Spring 4.3.11.RELEASE文档阅读(二):Core Technologies_AOP
虽然并不是每个问题都有答案,但我想了很多问题.so, just write it down , maybe one day...... AOP: 1,AOP是啥 2,AOP思想是怎么产生的 3,AOP ...
- jQuery实现当按下回车键时绑定点击事件
jQuery实现当按下回车键时绑定点击事件 <script> $(function(){ $(document).keydown(function(event){ if(event.key ...