51nod 1766
题意:给定一个树(10^5),m个询问(10^5),每次给定a,b,c,d,在区间[a,b]中选一个点,[c,d]选一个点,使得这两个点距离最大,输出最大距离。
题解:首先,我们有一个结论:对于一个集合的直径,如果我们将这个集合分解成两个非空集合,它的端点一定在两个非空集合的两个端这4个端点中。这非常的显然。。。
那么我们就可以做到合并两个集合,我们就可以用线段树维护每个区间的直径,就好啦,完全不用复杂的数据结构。
这道题卡时间,所以LCA要用欧拉序RMQ做。
复杂度O(nlogn)
#include<bits/stdc++.h>
using namespace std;
#define N 200005
inline int read(){
int x=,f=; char a=getchar();
while(a<'' || a>'') {if(a=='-') f=-; a=getchar();}
while(a>='' && a<='') x=x*+a-'',a=getchar();
return x*f;
}
int n,m,cnt=,euler[*N],dep[N],head[N],fi[N],dis[N],st[N][],mn[N][],Log[*N];
struct edges{
int to,c,next;
}e[N];
struct node{
int x1,x2,l,r;
}seg[*N];
struct data{
int x1,x2;
};
inline int getdis(int u,int v){
if(!u || !v) return ;
u=fi[u]; v=fi[v];
if(u>v) swap(u,v);
int p,len=Log[v-u+];
p=mn[u][len]<mn[v-(<<len)+][len]?st[u][len]:st[v-(<<len)+][len];
return dis[euler[u]]+dis[euler[v]]-*dis[p];
}
inline void update(int x){
int mx=,x1=seg[x<<].x1,x2=seg[x<<].x2,x3=seg[x<<|].x1,x4=seg[x<<|].x2,f;
if((f=getdis(x1,x2))>mx) seg[x].x1=x1,seg[x].x2=x2,mx=f; if((f=getdis(x1,x3))>mx) seg[x].x1=x1,seg[x].x2=x3,mx=f;
if((f=getdis(x1,x4))>mx) seg[x].x1=x1,seg[x].x2=x4,mx=f; if((f=getdis(x2,x3))>mx) seg[x].x1=x2,seg[x].x2=x3,mx=f;
if((f=getdis(x2,x4))>mx) seg[x].x1=x2,seg[x].x2=x4,mx=f; if((f=getdis(x3,x4))>mx) seg[x].x1=x3,seg[x].x2=x4,mx=f;
}
inline void insert(){
int u=read(),v=read(),c=read();
e[++cnt]=(edges){v,c,head[u]};head[u]=cnt;
}
void dfs(int x,int fa){
dep[x]=dep[fa]+; fi[x]=euler[]+;
for(int i=head[x];i;i=e[i].next){
if(fa==e[i].to) continue;
euler[++euler[]]=x;
dis[e[i].to]=dis[x]+e[i].c; dfs(e[i].to,x);
}
euler[++euler[]]=x;
}
inline void rmq_pre(){
for(int i=;i<=euler[];i++) st[i][]=euler[i],mn[i][]=dep[euler[i]];
for(int i=;i<=;i++)
for(int j=;j<=euler[];j++){
if(j+(<<i)->euler[]) break;
if(mn[j][i-]<mn[j+(<<(i-))][i-]) st[j][i]=st[j][i-],mn[j][i]=mn[j][i-];
else st[j][i]=st[j+(<<(i-))][i-],mn[j][i]=mn[j+(<<(i-))][i-];
}
Log[]=-; for(int i=;i<=euler[];i++) Log[i]=Log[i>>]+;
}
void build(int l,int r,int x){
seg[x].l=l; seg[x].r=r;
if(l==r) {seg[x].x1=l; seg[x].x2=; return;}
int mid=(l+r)>>;
build(l,mid,x<<);
build(mid+,r,x<<|);
update(x);
}
data merge(data tmp1,data tmp2){
int f,mx=,x1=tmp1.x1,x2=tmp1.x2,x3=tmp2.x1,x4=tmp2.x2;
data ret;
if((f=getdis(x1,x2))>mx) ret.x1=x1,ret.x2=x2,mx=f; if((f=getdis(x1,x3))>mx) ret.x1=x1,ret.x2=x3,mx=f;
if((f=getdis(x1,x4))>mx) ret.x1=x1,ret.x2=x4,mx=f; if((f=getdis(x2,x3))>mx) ret.x1=x2,ret.x2=x3,mx=f;
if((f=getdis(x2,x4))>mx) ret.x1=x2,ret.x2=x4,mx=f; if((f=getdis(x3,x4))>mx) ret.x1=x3,ret.x2=x4,mx=f;
return ret;
}
data query(int L,int R,int x){
int l=seg[x].l,r=seg[x].r;
if(l==L && r==R) {return (data){seg[x].x1,seg[x].x2};}
int mid=(l+r)>>;
if(R<=mid) return query(L,R,x<<);
else if(mid<L) return query(L,R,x<<|);
else return merge(query(L,mid,x<<),query(mid+,R,x<<|));
}
int main(){
n=read();
for(int i=;i<n;i++) insert();
dfs(,); rmq_pre(); build(,n,);
m=read();
while(m--){
int t1,t2,a=read(),b=read(),c=read(),d=read();
data tmp1=query(a,b,),tmp2=query(c,d,);
t1=max(getdis(tmp1.x1,tmp2.x1),getdis(tmp1.x1,tmp2.x2));
t2=max(getdis(tmp1.x2,tmp2.x1),getdis(tmp1.x2,tmp2.x2));
printf("%d\n",max(t1,t2));
}
return ;
}
51nod 1766的更多相关文章
- 51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径
51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径 题面 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即 ...
- [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)
[51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...
- 51Nod 1766 树上的最远点对
Description 一棵树,询问两个端点编号分别在在 \([a,b]\) 和 \([c,d]\) 两个区间中的最长链. Sol 线段树+ST表. 树上最长链可以合并,只需要合并两个区间最长链的两个 ...
- 51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)
题目链接 \(Description\) 给定一棵树.每次询问给定\(a\sim b,c\sim d\)两个下标区间,从这两个区间中各取一个点,使得这两个点距离最远.输出最远距离. \(n,q\leq ...
- 51nod 1766 树上的最远点对(线段树)
像树的直径一样,两个集合的最长路也是由两个集合内部的最长路的两个端点组成的,于是我们知道了两个集合的最长路,枚举一下两两端点算出答案就可以合并了,所以就可以用线段树维护一个区间里的最长路了. #inc ...
- 51nod 1766 树上的最远点对——线段树
n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j& ...
- 【树形结构】51nod 1766 树上的最远点对
题目内容 \(n\)个点被\(n−1\)条边连接成了一颗树,边有权值\(w_i\).有\(q\)个询问,给出\([a,b]\)和\([c,d]\)两个区间,表示点的标号请你求出两个区间内各选一点之间的 ...
- 倍增/线段树维护树的直径 hdu5993/2016icpc青岛L
题意: 给一棵树,每次询问删掉两条边,问剩下的三棵树的最大直径 点10W,询问10W,询问相互独立 Solution: 考虑线段树/倍增维护树的直径 考虑一个点集的区间 [l, r] 而我们知道了有 ...
- 【51nod】1766 树上的最远点对
[题意]给定n个点的树,m次求[a,b]和[c,d]中各选出一个点的最大距离.abcd是标号区间,n,m<=10^5 [算法]LCA+树的直径理论+线段树 [题解] 树的直径性质:距离树上任意点 ...
随机推荐
- 2017.2.28 activiti实战--第六章--任务表单(一)动态表单
学习资料:<Activiti实战> 第六章 任务表单(一)动态表单 内容概览:本章要完成一个OA(协同办公系统)的请假流程的设计,从实用的角度,讲解如何将activiti与业务紧密相连. ...
- CentOS下配置iptables防火墙 linux NAT(iptables)配置
CentOS下配置防火墙 配置nat转发服务CentOS下配置iptables防火墙 linux NAT(iptables)配置 CentOS下配置iptables 1,vim /etc/syscon ...
- haproxy mod tcp配置 按hostname 来定向服务器
需求 tcp 链接服务器, 服务器端根据不同的域名 定向到不同的内网服务器上: 参考资料 https://serverfault.com/questions/643131/proxying-tcp-b ...
- ionic 调试 "死亡白屏"
死亡白屏(White Screen of Death) 我想“死亡白屏”应该是不需要解释的,开发过ionic app的童鞋应该都有遇到过,这里解释以防读者没有听说过:“可能在浏览器中调试时一切正常,当 ...
- ES6 rest与扩展运算符
1.rest 变量将多余的参数放入数组中. function add(...values) { let sum = 0; for (var val of values) { sum += val; } ...
- STM32单片机和51单片机区别
单片机 / AVR / PIC / STM32 / 8051803189C5189S51 6905 单片机简介 单片微型计算机简称单片机,简单来说就是集CPU(运算.控制).RAM(数据存储-内存). ...
- opencv3.3.1 opencv_contribut 3.3.1 git 20180117最新版的在ubuntu1604上的编译
过程: 1. git clone ... contribut 2. git clone ... opencv 3. git checkout -b v3.3.1 4 gi ...
- c# .net 关于接口实现方式:隐式实现/显式实现!
以前在用到接口时,从来没注意到接口分为隐式实现与显示实现.昨天在浏览博客时看到相关内容,现在根据自己的理解记录一下,方便日后碰到的时候温习温习. 通俗的来讲,“显示接口实现”就是使用接口名称作为方法 ...
- 向oracle中插入date时,持久层sql怎么写???
public class EmpDao { public void addEmp(Emp emp) throws SQLException { QueryRunner runner = new Que ...
- Hive总结(四)hive安装记录
本篇为安装篇较简单: 前提: 1: 安装了hadoop-1.0.4(1.0.3也能够)正常执行 2:安装了hbase-0.94.3, 正常执行 接下来,安装Hive,基于已经安装好的hadoop.过程 ...