【题意】给定n个点的树,m次求[a,b]和[c,d]中各选出一个点的最大距离。abcd是标号区间,n,m<=10^5

【算法】LCA+树的直径理论+线段树

【题解】

树的直径性质:距离树上任意点最远的点一定是直径的一端。此结论在点集中依然试用。

那么根据性质,容易得到答案路径的两端一定是[a,b]直径的一端和[c,d]直径的一端的连线

(考虑任意一个点集AB的点,在点集A中距离最远的是a或b,在点集B中距离最远的是c或d,故直径的端点只能是abcd)

从而,两个区间的直径可以快速合并成一个区间的直径,即直径的可并性

因为直径可并和区间标号连续,所以可以用线段树维护一段区间的直径并查询。

连线用LCA解决,倍增常数较大会TLE,使用树链剖分或RMQ-LCA皆可。

复杂度O(n log2n)。

【注意】

RMQ查询时注意判断l>r时swap。

线段树合并时要从左右子树内部取答案,而询问不能从内部取答案。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn=;
int read(){
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
int first[maxn],a[maxn*],b[maxn],logs[maxn*],d[maxn*][],p[maxn*][],deep[maxn],dis[maxn],tot,cnt;
int L[maxn*],R[maxn*],n,m;
struct edge{int v,w,from;}e[maxn*];
struct cyc{int num,A,B;}t[maxn*]; int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a<b?b:a;}
void insert(int u,int v,int w){cnt++;e[cnt].v=v;e[cnt].w=w;e[cnt].from=first[u];first[u]=cnt;}
void dfs(int x,int fa){
a[++tot]=x;b[x]=tot;
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
deep[e[i].v]=deep[x]+;
dis[e[i].v]=dis[x]+e[i].w;
dfs(e[i].v,x);
a[++tot]=x;
}
}
void RMQ_init(){
logs[]=-;for(int i=;i<=tot;i++)logs[i]=logs[i>>]+;
for(int i=;i<=tot;i++)d[i][]=deep[a[i]],p[i][]=i;
for(int j=;(<<j)<=tot;j++){
for(int i=;i+(<<j)-<=tot;i++)if(d[i][j-]<d[i+(<<(j-))][j-]){
d[i][j]=d[i][j-];p[i][j]=p[i][j-];
}else{d[i][j]=d[i+(<<(j-))][j-];p[i][j]=p[i+(<<(j-))][j-];}
}
}
int lca(int l,int r){
l=b[l],r=b[r];
if(l>r)swap(l,r);//
int k=logs[r-l+];
k=d[l][k]<d[r-(<<k)+][k]?p[l][k]:p[r-(<<k)+][k];
return dis[a[l]]+dis[a[r]]-*dis[a[k]];
}
cyc tr(bool ok,cyc L,cyc R){
cyc x=(cyc){-,,};
if(!ok){
if(L.A==)return R;
if(R.A==)return L;
x=L;
if(R.num>x.num)x=R;
}
int num=lca(L.A,R.A);
if(num>x.num)x=(cyc){num,L.A,R.A};
num=lca(L.A,R.B);
if(num>x.num)x=(cyc){num,L.A,R.B};
num=lca(L.B,R.A);
if(num>x.num)x=(cyc){num,L.B,R.A};
num=lca(L.B,R.B);
if(num>x.num)x=(cyc){num,L.B,R.B};
return x;
}
void build(int k,int l,int r){
L[k]=l;R[k]=r;
if(l==r)t[k]=(cyc){,l,r};
else{
int mid=(l+r)>>;
build(k<<,l,mid);build(k<<|,mid+,r);
t[k]=tr(,t[k<<],t[k<<|]);
}
}
cyc ask(int k,int l,int r){
if(l<=L[k]&&R[k]<=r)return t[k];
else{
int mid=(L[k]+R[k])>>;
cyc x=(cyc){,,};
if(l<=mid)x=ask(k<<,l,r);
if(r>mid)x=tr(,x,ask(k<<|,l,r));
return x;
}
}
int main(){
n=read();
for(int i=;i<n;i++){
int u=read(),v=read(),w=read();
insert(u,v,w);insert(v,u,w);
}
tot=;dfs(,);RMQ_init();build(,,n);
m=read();
for(int i=;i<=m;i++){
int x=read(),y=read(),z=read(),w=read();
cyc q=tr(,ask(,x,y),ask(,z,w));
printf("%d\n",q.num);
}
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 树上的最远点对——线段树

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

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

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

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

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

  7. 51 nod 1766 树上的最远点对(线段树+lca)

    1766 树上的最远点对 基准时间限制:3 秒 空间限制:524288 KB 分值: 80 难度:5级算法题   n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个 ...

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

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

  9. 51Nod1766 树上的最远点对

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

随机推荐

  1. Scrum团队 《构建之法》第6~7章

    Scrum团队成立 团队名称: 22# 团队目标:做好每次布置的任务 还有提升自己 团队口号:做好现在,展望未来 团队成员:陈楷淇,张裕发,陈泽展,彭一建 角色分配 产品负责人(决定开发内容和优先级排 ...

  2. 简易版本vue的实现和注解

    本文参考的是前辈的简易版本Vue实现:http://www.cnblogs.com/canfoo/p/6891868.html,感谢.前辈GitHub地址:https://github.com/can ...

  3. linux 无交互生成ssh rsa免秘证书

    [root@xxx tmp]# man ssh-keygen NAME ssh-keygen - authentication key generation, management and conve ...

  4. 字符串(string)与整型(int)、浮点型(float)等之间的转换

    #include <stdlib.h> 1.int/float to string/array: C语言提供了几个标准库函数,可以将任意类型(整型.长整型.浮点型等)的数字转换为字符串,下 ...

  5. PGM学习之六 从有向无环图(DAG)到贝叶斯网络(Bayesian Networks)

    本文的目的是记录一些在学习贝叶斯网络(Bayesian Networks)过程中遇到的基本问题.主要包括有向无环图(DAG),I-Maps,分解(Factorization),有向分割(d-Separ ...

  6. CF992C Nastya and a Wardrobe

    我是题面 题意很清晰,这种题,我们当然还是有两种方法来做啦 方法一:找规律 读完题我们来看样例,通过样例一已我们大概可以看出,答案或许是\(n*2^{k+1}\) 肯定不能这么简单对吧,那就来看样例二 ...

  7. PHP中文字符gbk编码与UTF-8编码的转换

    通常PHP中上传文件,如果文件名称有中文字符,上传之后的名称是无法写入到本地的,因为上传来的编码格式一般是UTF-8的格式,这种格式是无法给文件命名并且存储到操作系统磁盘.在写入之前需要将其转换为gb ...

  8. 【BZOJ4242】水壶(克鲁斯卡尔重构树,BFS)

    [BZOJ4242]水壶(克鲁斯卡尔重构树,BFS) 题面 BZOJ然而是权限题. Description JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长 ...

  9. BZOJ 1013 | 一份写了一堆注释的高斯消元题解

    题意 给出\(n\)维直角坐标系中\(n + 1\)个点的坐标,它们都在一个\(n\)维球面上,求球心坐标. 题解 设球面上某两个点坐标为\((a_1, a_2, ... a_n)\)和\((b_1, ...

  10. 51nod 1353 树 | 树形DP经典题!

    51nod 1353 树 | 树形DP好题! 题面 切断一棵树的任意条边,这棵树会变成一棵森林. 现要求森林中每棵树的节点个数不小于k,求有多少种切法. 数据范围:\(n \le 2000\). 题解 ...