原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1766.html

题目传送门 - 51Nod1766

题意

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

题解

  只需要得到两个结论:

  设 S(A) 为点集 A 的最远点对所包含的点的集合。

  1. $S(A\cap B) \subset S(A)\cap S(B)$

  2. 强制点对的两端点分别在集合 A,B 时,最终的点对就从 A,B 中各选一个,取距离最大的就好了。

  于是只需要线段树维护一下区间最远点对即可。

  时间复杂度 $O(n\log n)$ 。

代码

#include <bits/stdc++.h>
using namespace std;
int read(){
int x=0;
char ch=getchar();
while (!isdigit(ch))
ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
const int N=100005,INF=1.05e9;
struct Gragh{
static const int M=N*2;
int cnt,y[M],z[M],nxt[M],fst[N];
void clear(){
cnt=1;
memset(fst,0,sizeof fst);
}
void add(int a,int b,int c){
y[++cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
}
}g;
#define list __zzd001
int n;
int fa[N][20],depth[N],ld[N],Log[N*2];
int ST[N*2][20],list[N*2],dfn=0,in[N],out[N];
void dfs(int x,int pre,int d,int dd){
depth[x]=d,fa[x][0]=pre,ld[x]=dd;
list[in[x]=++dfn]=x;
for (int i=1;i<20;i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for (int i=g.fst[x];i;i=g.nxt[i])
if (g.y[i]!=pre){
dfs(g.y[i],x,d+1,dd+g.z[i]);
list[++dfn]=x;
}
out[x]=dfn;
}
int spmax(int a,int b){
return depth[a]<depth[b]?a:b;
}
void prework(){
for (int i=1;i<=dfn;i++){
ST[i][0]=list[i];
for (int j=1;j<20;j++){
ST[i][j]=ST[i][j-1];
if (i-(1<<(j-1))>0)
ST[i][j]=spmax(ST[i][j-1],ST[i-(1<<(j-1))][j-1]);
}
}
}
int query(int L,int R){
int d=Log[R-L+1];
return spmax(ST[L+(1<<d)-1][d],ST[R][d]);
}
int LCA(int x,int y){
return query(min(in[x],in[y]),max(in[x],in[y]));
}
#define fi first
#define se second
#define pii pair <int,int>
pii t[N<<2];
int dis(int x,int y){
if (!~x&&!~y)
return -2*INF;
if (!~x||!~y)
return -INF;
return ld[x]+ld[y]-2*ld[LCA(x,y)];
}
pii Merge(pii a,pii b){
pii res=dis(a.fi,a.se)>dis(b.fi,b.se)?a:b;
if (dis(a.fi,b.fi)>dis(res.fi,res.se))res=make_pair(a.fi,b.fi);
if (dis(a.fi,b.se)>dis(res.fi,res.se))res=make_pair(a.fi,b.se);
if (dis(a.se,b.fi)>dis(res.fi,res.se))res=make_pair(a.se,b.fi);
if (dis(a.se,b.se)>dis(res.fi,res.se))res=make_pair(a.se,b.se);
return res;
}
void build(int rt,int L,int R){
if (L==R){
t[rt]=make_pair(L,-1);
return;
}
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
build(ls,L,mid);
build(rs,mid+1,R);
t[rt]=Merge(t[ls],t[rs]);
}
pii query(int rt,int L,int R,int xL,int xR){
if (R<xL||L>xR)
return make_pair(-1,-1);
if (xL<=L&&R<=xR)
return t[rt];
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
return Merge(query(ls,L,mid,xL,xR),query(rs,mid+1,R,xL,xR));
}
int main(){
n=read();
g.clear();
for (int i=1;i<n;i++){
int a=read(),b=read(),c=read();
g.add(a,b,c);
g.add(b,a,c);
}
dfs(1,0,0,0);
Log[1]=0;
for (int i=2;i<=dfn;i++)
Log[i]=Log[i>>1]+1;
prework();
build(1,1,n);
int m=read();
while (m--){
int a=read(),b=read(),c=read(),d=read();
pii x=query(1,1,n,a,b);
pii y=query(1,1,n,c,d);
pii res=make_pair(-1,-1);
if (dis(x.fi,y.fi)>dis(res.fi,res.se))res=make_pair(x.fi,y.fi);
if (dis(x.fi,y.se)>dis(res.fi,res.se))res=make_pair(x.fi,y.se);
if (dis(x.se,y.fi)>dis(res.fi,res.se))res=make_pair(x.se,y.fi);
if (dis(x.se,y.se)>dis(res.fi,res.se))res=make_pair(x.se,y.se);
printf("%d\n",dis(res.fi,res.se));
}
return 0;
}

  

51Nod1766 树上的最远点对 ST表 LCA 线段树的更多相关文章

  1. 「LuoguP3865」 【模板】ST表 (线段树

    题目背景 这是一道ST表经典题——静态区间最大值 请注意最大数据时限只有0.8s,数据强度不低,请务必保证你的每次查询复杂度为 O(1) 题目描述 给定一个长度为 N 的数列,和 M 次询问,求出每一 ...

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

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

  3. 51Nod1766 树上的最远点对

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

  4. 【做题】51Nod1766树上的最远点对——直径&线段树

    原文链接 https://www.cnblogs.com/cly-none/p/9890837.html 题意:给出一棵大小为\(n\)的树,边有边权.\(m\)次询问,每次给出两个标号区间\([a, ...

  5. 【BZOJ3784】树上的路径 点分治序+ST表

    [BZOJ3784]树上的路径 Description 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a< ...

  6. BZOJ 2006: [NOI2010]超级钢琴 [ST表+堆 | 主席树]

    题意: 一个序列,求k个不相同的长度属于\([L,R]\)的区间使得和最大 前缀和,对于每个r找最小的a[l] 然后我yy了一个可持久化线段树做法...也许会T 实际上主席树就可以了,区间k小值 然后 ...

  7. 【洛谷3865】 【模板】ST表(猫树)

    传送门 洛谷 Solution 实测跑的比ST表快!!! 这个东西也是\(O(1)\)的,不会可以看我上一篇Blog 代码实现 代码戳这里

  8. hihocoder-1347 小h的树上的朋友(lca+线段树)

    题目链接: 小h的树上的朋友 时间限制:18000ms 单点时限:2000ms 内存限制:512MB 描述 小h拥有n位朋友.每位朋友拥有一个数值Vi代表他与小h的亲密度.亲密度有可能发生变化. 岁月 ...

  9. 2019CCPC网络赛 C - K-th occurrence HDU - 6704(后缀数组+ST表+二分+主席树)

    题意 求区间l,r的子串在原串中第k次出现的位置. 链接:https://vjudge.net/contest/322094#problem/C 思路 比赛的时候用后缀自动机写的,TLE到比赛结束. ...

随机推荐

  1. 【原创】编程基础之Ruby

    ruby2.6.2 官方:https://www.ruby-lang.org/en/ 一 简介 A dynamic, open source programming language with a f ...

  2. wireshark找(检测)不到(捕获)网卡的解决办法

    1 前言 有时候打开wireshark,会提示找不到可用网卡,此时是因为NetGroup Packet Filter Driver 服务没有开启. 环境:笔记本 系统:Win10 网络:WIFI 2  ...

  3. [PHP]一些坑

    一.如果有一个字符串变量等于'error',它跟0 == 运算时,会返回true,但是它并不是一个预置常量 $test = 'error'; var_dump($test == 0);//true 二 ...

  4. centos6.5 有趣但是没有用的linux命令

    小火车 get http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm rpm -ivh epel-rele ...

  5. ie.360,qq浏览器这种ie内核浏览器默认阻止弹窗

  6. Confluence 6 针对站点维护使用只读模式

    如果你需要对 Confluence 进行维护,但是 Confluence 还是在运行或者你计划将站点合并到一个新的站点,你可以将你的 Confluence 站点设置为只读模式来限制用户在你站点中可以使 ...

  7. Confluence 6 数据库表-系统信息(System information)

    这些表格有存储数据相关的状态和 Confluence 站点的相关配置信息. confversion 被用来在升级系统的时候确定那个数据库的版本应该使用,这个表格只对数据库升级有影响. pluginda ...

  8. Confluence 6 升级 Confluence 使用数据源

    如果你对 Confluence 进行升级(手动或者使用安装器),你需要: 停止 Confluence (如果你已经尝试开始启动). 拷贝你的数据库驱动到 <installation-direct ...

  9. Swift 中 insetBy(dx: CGFloat, dy: CGFloat) -> CGRect 用法详解

    insetBy(dx: CGFloat, dy: CGFloat) -> CGRect 点击头文件进去 可以发现它是返回的一个CGRect insetBy方法是CGRect 的一个方法 dx后面 ...

  10. day11 函数的位置形参,位置实参,可变长位置形参,关键字形参

    今天内容 函数的参数详解 形参与实参 形参及形式参数,就是在定义函数是括号中指定的参数(本质就是一个名字) 实参及实际参数,指的是在调用函数是传入的参数)(本质就是一个值) 在调用函数是就会把形参和实 ...