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

题面

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

Input

第一行一个数字 n n<=100000。

第二行到第n行每行三个数字描述路的情况, x,y,z (1<=x,y<=n,1<=z<=10000)表示x和y之间有一条长度为z的路。

第n+1行一个数字m,表示询问次数 m<=100000。

接下来m行,每行四个数a,b,c,d。

Output

共m行,表示每次询问的最远距离

题解

刚才写了一大长串题解,好顿证明,发现证错了……

算了我不知道这玩意怎么证了(ノಠ益ಠ)ノ彡┻━┻

反正树上的一个“点的集合”的直径的端点,一定包含于把这个集合分成两部分、分别得到的直径的端点(共四个)中。

那么可以用线段树维护区间内直径的端点。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
template <class T>
void read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
} const int N = 100005;
int n, m;
int ecnt, adj[N], nxt[2*N], go[2*N], w[2*N];
int dep[N], pos[N], lst[2*N], idx, mi[2*N][20], lg[2*N];
struct Data {
int fi, se;
} data[4*N];
void add(int u, int v, int ww){
go[++ecnt] = v;
nxt[ecnt] = adj[u];
adj[u] = ecnt;
w[ecnt] = ww;
}
void dfs(int u, int pre){
lst[++idx] = u, pos[u] = idx;
for(int e = adj[u], v; e; e = nxt[e])
if(v = go[e], v != pre)
dep[v] = dep[u] + w[e], dfs(v, u), lst[++idx] = u;
}
int Min(int a, int b){
return dep[a] > dep[b] ? b : a;
}
int lca(int u, int v){
int l = pos[u], r = pos[v];
if(l > r) swap(l, r);
int j = lg[r - l + 1];
return Min(mi[l][j], mi[r - (1 << j) + 1][j]);
}
void st_init(){
for(int i = 1, j = 0; i <= idx; i++){
if(1 << (j + 1) == i) j++;
lg[i] = j;
}
for(int i = 1; i <= idx; i++)
mi[i][0] = lst[i];
for(int j = 1; (1 << j) <= idx; j++)
for(int i = 1; i + (1 << j) - 1 <= idx; i++)
mi[i][j] = Min(mi[i][j - 1], mi[i + (1 << (j - 1))][j - 1]);
}
int dis(int u, int v){
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}
Data Max(Data a, Data b){
int t[4] = {a.fi, a.se, b.fi, b.se}, mx = 0;
Data ret;
for(int i = 0; i < 4; i++)
for(int j = i + 1; j < 4; j++)
if(dis(t[i], t[j]) > mx)
mx = dis(t[i], t[j]), ret.fi = t[i], ret.se = t[j];
return ret;
}
void build(int k, int l, int r){
if(l == r) return (void)(data[k] = (Data){l, l});
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
data[k] = Max(data[k << 1], data[k << 1 | 1]);
}
Data query(int k, int l, int r, int ql, int qr){
if(ql <= l && qr >= r) return data[k];
int mid = (l + r) >> 1;
if(qr <= mid) return query(k << 1, l, mid, ql, qr);
if(ql > mid) return query(k << 1 | 1, mid + 1, r, ql, qr);
return Max(query(k << 1, l, mid, ql, qr), query(k << 1 | 1, mid + 1, r, ql, qr));
} int main(){
read(n);
for(int i = 1, u, v, ww; i < n; i++)
read(u), read(v), read(ww), add(u, v, ww), add(v, u, ww);
dfs(1, 0);
st_init();
build(1, 1, n);
read(m);
while(m--){
int a, b, c, d, ans = 0;
read(a), read(b), read(c), read(d);
Data x = query(1, 1, n, a, b), y = query(1, 1, n, c, d);
ans = max(dis(x.fi, y.fi), dis(x.fi, y.se));
ans = max(ans, max(dis(x.se, y.fi), dis(x.se, y.se)));
write(ans), puts("");
}
return 0;
}

51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. 51nod 1593 公园晨跑 | ST表(线段树?)思维题

    51nod 1593 公园晨跑 有一只猴子,他生活在一个环形的公园里.有n棵树围绕着公园.第i棵树和第i+1棵树之间的距离是 di ,而第n棵树和第一棵树之间的距离是 dn .第i棵树的高度是 hi ...

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

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

随机推荐

  1. [硬件配置]Ubuntu 16.04下使用NETGEAR Nighthawk AC1900 (A7000) WIFi USB适配器

    为了增强无人机与地面站之间的传输信号,组里买了这款WiFi信号接收器,无奈只有Windows和Mac OS版本的驱动程序.后来不知道从哪里得来的一个偏方可以安装Ubuntu下的驱动,特此记录. 内核降 ...

  2. OpenGL 笔记<1> 固定管线实例 + 双缓存测试实例

    欲以此分类来记录opengl的学习历程,此为第一篇,所以先来一个固定管线的例子,以及对双缓存的测试. 一.配置环境 写之前,先进行配置,然后再讲内容. 注:第一部分涉及的代码均忽略. [环境配置传送门 ...

  3. Unity Shader 学习之旅

    Unity Shader 学习之旅 unityshader图形图像 纸上学来终觉浅,绝知此事要躬行 美丽的梦和美丽的诗一样 都是可遇而不可求的——席慕蓉 一.渲染流水线 示例图 Tips:什么是 GP ...

  4. 你这一辈子要用到的C数学函数都在这

       两数相加  #include <stdio.h> int main(void){ int a = 10;  //定义变量a, 把10 赋值给a int b = 20;  //定义变量 ...

  5. php快速上手总结

    PHP作为现代热门主流的开发语言,对于那些想加入新手PHPer,从哪学起,如何学习?你必须要需要掌握PHP的基础知识,基础知识相当于重点,是不可忽视的知识.常用的功能模块,面向对象的,MVC等相关技能 ...

  6. PHP核心技术——反射

    反射: 反射指在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类.方法.属性.参数等的详细信息,包括注释.这种动态获取信息以及动态调用对象方法的功能称为反射API class person{ ...

  7. 32bit 天堂2服务端多机负载

    第一步..先确定..单机架设成功.. 第二步..复制整个服务器端文件到第2个服务器 第3步.. 将你C:\Program Files\Common Files\ODBC\Data Sources 中的 ...

  8. linux执行命令返回码释义

    Linux 操作系统错误代码解释 0.错误代码1-10 OS error code 0: Success 操作系统错误代码0:成功 OS error code 1: Operation not per ...

  9. Netty源码分析第4章(pipeline)---->第4节: 传播inbound事件

    Netty源码分析第四章: pipeline 第四节: 传播inbound事件 有关于inbound事件, 在概述中做过简单的介绍, 就是以自己为基准, 流向自己的事件, 比如最常见的channelR ...

  10. 2-First scrum meeting-20151201

    前言 因为编译和数据库的影响,这学期的担子差点抗不起来……所以在老师的同情之下我们的第二阶段从今天开始正式开工.因为scrum meeting要求更新,所以配合其他作业,完成功能可能细化到模块部分. ...