题目内容

\(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. PDF启动增加字段

    ALTER TABLE `cnoa_system_fs` ADD `reviewStatus` INT(1) NOT NULL DEFAULT '0' AFTER `isArchive`;ALTER  ...

  2. 企业邮箱选择,商务办公为什么选TOM企业邮箱?

    企业邮箱是工作中的重要工具,它可以帮助我们更规范的上传下达.更高效的管理工作,也是拓展合作伙伴的敲门砖及必杀技.比如写一封诚意满满的合作邀请,再比如重要关头写一封合作协议.毫不夸张,企业邮箱不仅能节省 ...

  3. 用了这个jupyter插件,我已经半个月没打开过excel了

    1 简介 jupyter lab是我迄今为止体验过开展数据分析等任务最舒适的平台,但这不代表它是完美的,因为在很多方面它仍然存在欠缺,譬如在对csv文件的交互式编辑方面. 图1 而本文将要介绍的jup ...

  4. SpringBoot打Jar包在命令行运行

    首先写一个测试文件 然后点击IDEA右侧的maven,然后选择package,之后点击上面运行或者直接双击即可, 等下方控制台构建成功即可: 然后找到项目目录下target下即可看到打的jar包 然后 ...

  5. Webpack 打包优化之体积篇

    谈及如今欣欣向荣的前端圈,不仅有各类框架百花齐放,如Vue, React, Angular等等,就打包工具而言,发展也是如火如荼,百家争鸣:从早期的王者Browserify, Grunt,到后来赢得宝 ...

  6. python基础:异常捕捉

    一.异常 python在程序运行过程中,可能会出现一些错误和异常,导致程序停止运行.我们可以通过捕捉异常,并对异常进行处理,使得程序可以正常运行 异常有很多类型,可以根据类型挨个捕捉.也可统一捕获: ...

  7. Django启动框架自带原始页面(Django一)

    1.安装,cmd中输入命令: pip install django (前提是python已安装完成,才可以使用pip这个python的库管理工具)ps:在cmd中使用pip命令安装时可能因为速度过慢而 ...

  8. react学习 | 踩坑指南

    react样式模块化的"omit -loader"坑 众所周知 react样式的模块化(css modules) 是自己模块中写自己的css,与其他模块互补影响,解决了命名冲突和全 ...

  9. Hive使用Calcite CBO优化流程及SQL优化实战

    目录 Hive SQL执行流程 Hive debug简单介绍 Hive SQL执行流程 Hive 使用Calcite优化 Hive Calcite优化流程 Hive Calcite使用细则 Hive向 ...

  10. spring cloud微服务快速教程之(十四)spring cloud feign使用okhttp3--以及feign调用参数丢失的说明

    0-前言 spring cloud feign 默认使用httpclient,需要okhttp3的可以进行切换 当然,其实两者性能目前差别不大,差别较大的是很早之前的版本,所以,喜欢哪个自己选择: 1 ...