本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

题目链接:codeforces804D

正解:二分$+DP$

解题报告:

  预处理出每个点所在的树内的最远点距离dis,考虑对于树$A$的点$x$,与树$B$的$y$产生的贡献就是$dis[x]+dis[y]+1$和两棵树的直径取一个$max$。

  对于$max$,我们显然可以分开考虑,当$dis[x]+dis[y]+1<$两棵树的直径,那么贡献就是直径的$max$。

  否则我们可以直接得到贡献。

  具体做法就是先对于每棵树内部的$dis$排序,然后每次枚举较小的连通块内的每个点,二分另一个连通块中的分界点位置就好了。

  看上去像个暴力,但是仔细想想,套上记忆化之后复杂度应该很靠谱,大概是根号左右。

//It is made by ljh2000
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <cmath>
#include <ctime>
#include <map>
#define lc root<<1
#define rc root<<1|1
#define reg(i,x) for(int i=first[x];i;i=nxt[i])
using namespace std;
typedef long long LL;
const int MAXN = 200011;
const int MAXM = 400011;
int n,m,q,ecnt,first[MAXN],nxt[MAXM],to[MAXM],size[MAXN],bel[MAXN],cnt,f[MAXN][2],D[MAXN];
double ans;
map<int,double>mp[MAXN];
vector<int>w[MAXN];
vector<int>w2[MAXN];
inline void link(int x,int y){ nxt[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
inline int getint(){
int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} inline void dfs(int x,int fa,int id){
bel[x]=id; size[id]++;
reg(i,x) {
int v=to[i]; if(v==fa) continue;
dfs(v,x,id);
if(f[v][0]+1>f[x][0]) f[x][1]=f[x][0],f[x][0]=f[v][0]+1;
else if(f[v][0]+1>f[x][1]) f[x][1]=f[v][0]+1;
}
D[id]=max(D[id],f[x][0]+f[x][1]);
} inline void dfs2(int x,int fa,int maxl){
int tmp=max(maxl,f[x][0]);
w[ bel[x] ].push_back(tmp);
w2[ bel[x] ].push_back(0);
reg(i,x) {
int v=to[i]; if(v==fa) continue;
if(f[v][0]+1==f[x][0]) dfs2(v,x,max(maxl,f[x][1])+1);
else dfs2(v,x,max(maxl,f[x][0])+1);
}
} inline int getp(int x,int val){
int l=0,r=w[x].size()-1,mid,pos;
if(val>w[x][r]) return r;
if(val<w[x][0]) return 0;
while(l<=r) {
mid=(l+r)>>1;
if(w[x][mid]<=val) pos=mid,l=mid+1;
else r=mid-1;
}
return pos+1;
} inline void work(){
n=getint(); m=getint(); q=getint(); int x,y,r1,r2;
for(int i=1;i<=m;i++) {
x=getint(); y=getint();
link(x,y); link(y,x);
} for(int i=1;i<=n;i++)
if(!bel[i]) {
dfs(i,0,++cnt);
dfs2(i,0,0);
} for(int i=1;i<=cnt;i++) sort(w[i].begin(),w[i].end());
for(int i=1;i<=cnt;i++) {
w2[i][ w2[i].size()-1 ]=w[i][ w[i].size()-1 ];
//printf("---%d\n",w2[i][ w[i].size()-1 ]);
for(int j=w2[i].size()-2;j>=0;j--) {
w2[i][j]=w2[i][j+1]+w[i][j];
//printf("---%d\n",w2[i][j]);
}
} while(q--) {
x=getint(); y=getint();
r1=bel[x]; r2=bel[y]; if(size[r1]>size[r2]) swap(r1,r2),swap(x,y);
if(mp[r1][r2]!=0) ans=mp[r1][r2];
else {
if(r1==r2) { puts("-1"); continue; }
int lim=max(D[r1],D[r2]),pos;
ans=0;
for(int i=0,ss=w[r1].size();i<ss;i++) {
pos=getp(r2,lim-1-w[r1][i]);
ans+=(double)pos*lim; if(pos<w[r2].size()) ans+=w2[r2][pos]+(w[r1][i]+1)*(w[r2].size()-pos);
}
ans/=size[r1];
ans/=size[r2];
mp[r1][r2]=ans;
}
printf("%.8lf\n",ans);
}
} int main()
{
#ifndef ONLINE_JUDGE
freopen("804.in","r",stdin);
freopen("804.out","w",stdout);
#endif
work();
return 0;
}

  

codeforces804D Expected diameter of a tree的更多相关文章

  1. Codeforces 840D Expected diameter of a tree 分块思想

    Expected diameter of a tree 我们先两次dfs计算出每个点能到达最远点的距离. 暴力计算两棵树x, y连边直径的期望很好求, 我们假设SZ(x) < SZ(y) 我们枚 ...

  2. 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 ...

  3. Codeforces 804D Expected diameter of a tree(树的直径 + 二分 + map查询)

    题目链接 Expected diameter of a tree 题目意思就是给出一片森林, 若把任意两棵树合并(合并方法为在两个树上各自任选一点然后连一条新的边) 求这棵新的树的树的直径的期望长度. ...

  4. CF804D Expected diameter of a tree 树的直径 根号分治

    LINK:Expected diameter of a tree 1e5 带根号log 竟然能跑过! 容易想到每次连接两个联通快 快速求出直径 其实是 \(max(D1,D2,f_x+f_y+1)\) ...

  5. Codeforces Round #411 (Div. 1) D. Expected diameter of a tree

    题目大意:给出一个森林,每次询问给出u,v,问从u所在连通块中随机选出一个点与v所在连通块中随机选出一个点相连,连出的树的直径期望(不是树输出-1).(n,q<=10^5) 解法:预处理出各连通 ...

  6. Codeforces 804D Expected diameter of a tree(树形DP+期望)

    [题目链接] http://codeforces.com/contest/804/problem/D [题目大意] 给你一个森林,每次询问给出u,v, 从u所在连通块中随机选出一个点与v所在连通块中随 ...

  7. CodeForces 805F Expected diameter of a tree 期望

    题意: 给出一个森林,有若干询问\(u, v\): 从\(u, v\)中所在子树中随机各选一个点连起来,构成一棵新树,求新树直径的期望. 分析: 回顾一下和树的直径有关的东西: 求树的直径 从树的任意 ...

  8. 543. Diameter of Binary Tree

    https://leetcode.com/problems/diameter-of-binary-tree/#/description Given a binary tree, you need to ...

  9. LeetCode 543. Diameter of Binary Tree (二叉树的直径)

    Given a binary tree, you need to compute the length of the diameter of the tree. The diameter of a b ...

随机推荐

  1. [py][mx]django-解决注册用户已存在,激活链接判断

    注册时候,如果用户已存在,则提示错误 激活用户时候,如果激活链接失效,则提示用户. class RegisterView(View): def get(self, request): register ...

  2. javascript本地,宿主,内置对象

    一.本地对象:官方定义的对象独立于宿主环境的 ECMAScript 实现提供的对象,包括操作系统和浏览器.本地对象就是 ECMA-262 定义的类(引用类型).“本地对象”包含内容:   Object ...

  3. http协议基础(七)通用首部字段

    通用首部字段的意思,就是:请求和响应报文双方都会使用的首部 1.Cache-Control 通过指定它的指令,能操作缓存的工作机制 指令参数是可选的,多个指令通过“,”分隔 Cache-Control ...

  4. 定时器事件QtimerEvent 随机数 qrand Qtimer定时器

    QTimerEvent类:定时器事件.QObject的子类都可使用  int QObject::startTimer(int interval)[参数:毫秒][返回值:定时器整型编号]来开启一个定时器 ...

  5. 如何在SQL Server查询语句(Select)中检索存储过程(Store Procedure)的结果集?

    如何在SQL Server查询语句(Select)中检索存储过程(Store Procedure)的结果集?(2006-12-14 09:25:36) 与这个问题具有相同性质的其他描述还包括:如何 ...

  6. mysql中delete和truncate区别

    delete和truncate区别如下: 一.灵活性:delete可以条件删除数据,而truncate只能删除表的所有数据: delete from table_test where ... trun ...

  7. Bus,Exclusive access,memory attribute

    指令LDREX,STREX是在armv6中新加的指令,配合AMBA3--AXI中的lock[1:0]信号. 在Atomic Access一节中是这么规定的:ARLOCK[1:0]/AWLOCK[1:0 ...

  8. FastReport问题整理(转)

    FastReport问题整理 博客分类: 软件开发   部分来自网上,部分来自网友,部分来自Demo如果有新的内容,会不断更新.. 更新历史: 2009-02-27 加入套打方案全攻略(原:jinzh ...

  9. 【Python】Python 网页爬虫 & 文本处理 & 科学计算 & 机器学习 & 数据挖掘兵器谱

    本文转载自:https://www.cnblogs.com/colipso/p/4284510.html 好文 mark http://www.52nlp.cn/python-%E7%BD%91%E9 ...

  10. 制作系统U盘,不用做任何动作直接从U盘启动装系统(非PE的)

    用U盘装系统可以用PE方式,进入PE系统,选择镜像文件,然后装,这种比较麻烦. 下面介绍一下从U盘启动,直接装系统的方法,这种方法从U盘启动后,不用做任何动作,就像用光盘装系统一样简单 首先要制作一下 ...