题目内容

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

\[\max \{ \text{dis}(i,j)\vert i\in[a,b],j\in [c,d] \}
\]

数据范围

\(1≤n,q≤10^5,1≤w_i≤10^4\)

思路

好像其实是很好写的一道题(虽然考场我写的暴力orz)

先想树的直径的合并性质:

若\(<a,b>\),\(<c,d>\)分别为原来两棵树的直径,那么合并后的新直径必定为\(<a,b>\),\(<c,d>\),\(<a,c>\),\(<a,d>\),\(<b,c>\),\(<b,d>\)中的最大值。

那么对于本题的路径合并也是类似,可以通过反证法证明。

假设原来的直径为\(<a,b>\),设合并之后的直径不是以\(a,b\)中的为端点而是\(<c,d>\),那么可以得出\(\text{dis}(b,d)\)和\(\text{dis}(a,d)\)均要小于\(\text{dis}(c,d)\)。可以看出\(<e,d>\)是公共的,那么可以得出\(\text{dis}(b,e)\)和\(\text{dis}(a,e)\)均小于\(\text{dis}(c,e)\),那么你一开始求直径的时候就会选择\(<b,c>\)或\(<a,c>\)其中一条,而不是\(<a,b>\)。

那么关于这个性质我们就可以开一个线段树,内存最大路径的端点下标,通过以上的性质合并。需要注意的是倍增求\(\text{LCA}\)常数太大会导致超时,所以可以选择树剖或\(\text{ST}\)表求\(\text{LCA}\)。

然后这里提供一种重载运算符的写法,感觉比直接写好多if少很多(但是本人习惯扩行qwq看起来和正常写法差不多),然后本人过于蒻所以不会\(\text{ST}\)表求\(\text{LCA}\)所以写的树剖。

代码

#include <bits/stdc++.h>
#define lson (rt<<1)
#define rson (rt<<1|1)
using namespace std;
const int maxn=1e5+10;
int n,m; struct Edge{
int from,to,w,nxt;
}e[maxn<<1]; inline int read(){
int x=0,fopt=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')fopt=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+ch-48;
ch=getchar();
}
return x*fopt;
} int head[maxn],cnt;
inline void add(int u,int v,int w){
e[++cnt].from=u;
e[cnt].to=v;
e[cnt].w=w;
e[cnt].nxt=head[u];
head[u]=cnt;
} int fa[maxn],dep[maxn],siz[maxn],dis[maxn],son[maxn];
void dfs1(int u){
dep[u]=dep[fa[u]]+1;siz[u]=1;
for(register int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa[u])continue;
fa[v]=u;
dis[v]=dis[u]+e[i].w;
dfs1(v);
siz[u]+=siz[v];
if(!son[u]||siz[v]>siz[son[u]])son[u]=v;
}
} int top[maxn];
void dfs2(int u,int t){
top[u]=t;
for(register int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa[u])continue;
dfs2(v,v==son[u]?t:v);
}
} inline int lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
} inline int Getdis(int u,int v){
return dis[u]+dis[v]-2*dis[lca(u,v)];
} struct Node{
int l,r;
friend inline Node operator +(const Node& A,const Node& B){
int p[4]={A.l,A.r,B.l,B.r};
int Max=-1;
Node res;
for(int i=0;i<4;i++)
for(int j=i+1;j<4;j++){
int w=Getdis(p[i],p[j]);
if(w>Max){
Max=w;
res=(Node){p[i],p[j]};
}
}
return res;
}
}tree[maxn<<2]; inline void pushup(int rt){
tree[rt]=tree[lson]+tree[rson];
} inline void Build(int rt,int l,int r){
if(l==r){
tree[rt].l=tree[rt].r=l;
return;
}
int mid=(l+r)>>1;
Build(lson,l,mid);
Build(rson,mid+1,r);
pushup(rt);
} inline Node query(int rt,int l,int r,int s,int t){
if(s<=l&&t>=r)
return tree[rt];
int mid=(l+r)>>1;
if(t<=mid)return query(lson,l,mid,s,t);
else if(s>=mid+1)return query(rson,mid+1,r,s,t);
else return query(lson,l,mid,s,mid)+query(rson,mid+1,r,mid+1,t);
} inline int Mymax(int a,int b,int c,int d){
return max(a,max(b,max(c,d)));
} int main(){
freopen("D.in","r",stdin);
freopen("D.out","w",stdout);
n=read();
for(register int i=1;i<n;i++){
int x=read(),y=read(),z=read();
add(x,y,z);
add(y,x,z);
} dfs1(1);
dfs2(1,1);
Build(1,1,n); m=read();
while(m--){
int a=read(),b=read(),c=read(),d=read();
Node x=query(1,1,n,a,b);
Node y=query(1,1,n,c,d);
int ans=Mymax(Getdis(x.l,y.l),Getdis(x.l,y.r),Getdis(x.r,y.l),Getdis(x.r,y.r));
printf("%d\n",ans);
}
return 0;
}

【树形结构】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. 51 nod 1766 树上的最远点对(线段树+lca)

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

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

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

  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. 初次使用maven创建web工程发现只有一个idea目录,src,webapp目录都不见了,解决方案

    修bug系列2之 初次使用maven创建web项目的src目录不知所踪 窗外下着下雨,屋内的我学着maven,本以为轻轻松松,没想到还是遇到了bug.好了不说了,来看看我是怎么解决的. 在初次使用ma ...

  2. linux 字符驱动框架(用户态的read,write,poll是怎么操作驱动的)

    前言 这篇文章是通过对一个简单字符设备驱动的操作来解释,用户态的读写操作是怎么映射到具体设备的. 因为针对不同版本的linux内核,驱动的接口函数一直有变化,这贴出我测试的系统信息: root@ubu ...

  3. [Leetcode]Sql系列3

    题目1 产品数据表: Products +---------------+---------+ | Column Name | Type | +---------------+---------+ | ...

  4. sql分页存储过程,带求和、排序

    创建存储过程: CREATE PROCEDURE [dbo].[sp_TBTest_Query] ( @PageSize INT, --每页多少条记录 @PageIndex INT = 1, --指定 ...

  5. Combine 框架,从0到1 —— 4.在 Combine 中使用 KVO

      本文首发于 Ficow Shen's Blog,原文地址: Combine 框架,从0到1 -- 4.在 Combine 中使用 KVO.   内容概览 前言 用 KVO 监控改动 将 KVO 代 ...

  6. hystrix(3) 熔断器

    讲完metrics我们就来了解一下熔断器的执行情况,熔断器的判断取决metrics数据. hystrix在执行命令前需要经过熔断器判断,如果服务被熔断,则执行fallback流程,熔断判断逻辑如下: ...

  7. Java Web学习(四)http协议

    文章更新时间:2020/07/24 一.概念 定义 HTTP:超文本传输协议,是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的过程. HTTP协议:用于定义客户端与 ...

  8. Docker数据卷和数据卷容器

    是什么 数据卷设计的目的,在于数据的永久化,他完全独立于容器的生存周期,因此,Docker不会在容器删除时删除其挂载的数据卷,也不会存在类似的垃圾收集机制对容器引用的数据卷进行处理.类似我们Redis ...

  9. synchronized和lock的作用与对比

    一.synchronized的作用 synchronized是java中的一个关键字,用于线程同步.1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象 ...

  10. springboot:This application has no explicit mapping for /erro

    springboot启动没有报错,但是访问的时候返回如上图的错误.看报错内容感觉是没有这个mapping对应的接口.但是确实写了. 最终发现是因为springboot的启动类放的位置不对.启动类所在的 ...