题意:给定一个树(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的更多相关文章

  1. 51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径

    51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径 题面 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即 ...

  2. [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)

    [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...

  3. 51Nod 1766 树上的最远点对

    Description 一棵树,询问两个端点编号分别在在 \([a,b]\) 和 \([c,d]\) 两个区间中的最长链. Sol 线段树+ST表. 树上最长链可以合并,只需要合并两个区间最长链的两个 ...

  4. 51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)

    题目链接 \(Description\) 给定一棵树.每次询问给定\(a\sim b,c\sim d\)两个下标区间,从这两个区间中各取一个点,使得这两个点距离最远.输出最远距离. \(n,q\leq ...

  5. 51nod 1766 树上的最远点对(线段树)

    像树的直径一样,两个集合的最长路也是由两个集合内部的最长路的两个端点组成的,于是我们知道了两个集合的最长路,枚举一下两两端点算出答案就可以合并了,所以就可以用线段树维护一个区间里的最长路了. #inc ...

  6. 51nod 1766 树上的最远点对——线段树

    n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j& ...

  7. 【树形结构】51nod 1766 树上的最远点对

    题目内容 \(n\)个点被\(n−1\)条边连接成了一颗树,边有权值\(w_i\).有\(q\)个询问,给出\([a,b]\)和\([c,d]\)两个区间,表示点的标号请你求出两个区间内各选一点之间的 ...

  8. 倍增/线段树维护树的直径 hdu5993/2016icpc青岛L

    题意: 给一棵树,每次询问删掉两条边,问剩下的三棵树的最大直径 点10W,询问10W,询问相互独立 Solution: 考虑线段树/倍增维护树的直径 考虑一个点集的区间 [l, r] 而我们知道了有 ...

  9. 【51nod】1766 树上的最远点对

    [题意]给定n个点的树,m次求[a,b]和[c,d]中各选出一个点的最大距离.abcd是标号区间,n,m<=10^5 [算法]LCA+树的直径理论+线段树 [题解] 树的直径性质:距离树上任意点 ...

随机推荐

  1. 【开发总结】—— BABYLON 3D开发常见问题及解决方法

    前言:组内同事们根据长时间的Babylon.js开发实践,一起将项目开发中遇到的问题及解决方法做了一个梳理. ios [最好] 关闭离线缓存—— 解决添加了反射的mesh 丢失的问题 不要使用 pos ...

  2. JAVA Eclipse开发Android如何让屏幕保持为竖直或水平状态

    在Manifest.xml文件中找到activity部分,添加下面这一行 android:screenOrientation="landscape" landscape是横向,po ...

  3. Andfix热修复框架原理及源代码解析-上篇

    热补丁介绍及Andfix的使用 Andfix热修复框架原理及源代码解析-上篇 Andfix热修复框架原理及源代码解析-下篇 1.不知道怎样使用的同学,建议看看我上一篇写的介绍热补丁和Andfix的使用 ...

  4. windows的iis做后门,隐藏访问,无日志

    windows下的iis5/iis6做后门,隐藏访问,不留访问记录或者不留日志 好不容易攻下一台Windows2000/2003 IIS服务器,你一定会想,怎样才能长期占有这个“肉鸡”呢?聪明的你肯定 ...

  5. xshell中配置linux密钥登陆

    参见 http://www.aiezu.com/system/linux/xshell_ssh_public-key_login.html 配置只能秘钥登陆 http://blog.csdn.net/ ...

  6. 【Python】继承

    子类的方法__init__() 创建子类的实例时,Python首先需要完成的任务是给父类所有属性赋值,为此,子类的方法__init__()需要父类施以援手. class Car(): '''模拟汽车' ...

  7. fiddler不能监听 localhost和 127.0.0.1的问题 .

    localhost/127.0.0.1的请求不会通过任何代理发送,fiddler也就无法截获. 解决方案 用 http://localhost. (locahost紧跟一个点号) 用 http://1 ...

  8. eclipse svn插件 删除原账号信息重新登录

    1.通过删除SVN客户端的账号配置文件    1)查看你的Eclipse中使用的是什么SVN Interface(中文:svn接口)windows > preference > Team ...

  9. Spring中的scope配置和@scope注解

    Scope,也称作用域,在 Spring IoC 容器是指其创建的 Bean 对象相对于其他 Bean 对象的请求可见范围.在 Spring IoC 容器中具有以下几种作用域:基本作用域(single ...

  10. 程序猿的量化交易之路(32)--Cointrade之Portfolio组合(19)

    转载须注明出处:http://blog.csdn.net/minimicall?viewmode=contents,http://cloudtrade.top/ Portfolio:组合,代表的是多个 ...