51Nod 1766 树上的最远点对
Description
一棵树,询问两个端点编号分别在在 \([a,b]\) 和 \([c,d]\) 两个区间中的最长链.
Sol
线段树+ST表.
树上最长链可以合并,只需要合并两个区间最长链的两个端点即可.
ST表要预处理好 \(log\) ,用了cmath 的 log2() ,T的飞起.
这样复杂度就是 \(O(nlogn)\)
Code
#include<cstdio>
#include<cmath>
#include<cstring>
#include<utility>
#include<vector>
#include<iostream>
using namespace std; #define debug(a) cout<<#a<<"="<<a<<" "
#define mpr make_pair
typedef pair< int,int > pr;
typedef long long LL;
const int N = 100050;
const int M = 25; int n,m,cnt;
vector< pr > g[N];
int pow2[M],lg2[N<<1],dfs[N<<1],d[N],val[N],pos[N];
int f[N<<1][M]; inline int in(int x=0,char ch=getchar()){ while(ch>'9' || ch<'0') ch=getchar();
while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x; }
void DFS(int u,int fa,int dep,int value){
dfs[++m]=u,d[u]=dep,val[u]=value,pos[u]=m,f[m][0]=u;
for(int i=0,v,lim=g[u].size();i<lim;i++) if((v=g[u][i].first)!=fa) DFS(v,u,dep+1,value+g[u][i].second),dfs[++m]=u,f[m][0]=u;
}
void init(){
pow2[0]=1;for(int i=1;i<M;i++) pow2[i]=pow2[i-1]<<1;
lg2[0]=-1;for(int i=1;i<=m;i++) lg2[i]=lg2[i>>1]+1;
for(int j=1;j<M;j++) for(int i=1;i<=m;i++) if(i+pow2[j]-1<=m){
int u=f[i][j-1],v=f[i+pow2[j-1]][j-1];
if(d[u]<d[v]) f[i][j]=u;else f[i][j]=v;
}
}
int Dis(int u,int v,int lca=0){
if(pos[u]<pos[v]) swap(u,v);int lg=lg2[pos[u]-pos[v]+1];
if(d[f[pos[v]][lg]]<d[f[pos[u]-pow2[lg]+1][lg]]) lca=f[pos[v]][lg];else lca=f[pos[u]-pow2[lg]+1][lg];
return (LL)val[u]+val[v]-2*val[lca];
}
struct SegmentTree{
#define lc (o<<1)
#define rc (o<<1|1)
#define mid ((l+r)>>1)
#define Gd(u) Dis(u.first,u.second)
pr g[N<<2];int d[N<<2];
pr PushUp(pr u,pr v,int d1=0,int d2=0,int o=0){
if(!d1 && !d2) d1=Gd(u),d2=Gd(v);
pr res=d1>d2?u:v;int dd=max(d1,d2);
if(Dis(u.first,v.first)>dd) res=mpr(u.first,v.first),dd=Gd(res);
if(Dis(u.first,v.second)>dd) res=mpr(u.first,v.second),dd=Gd(res);
if(Dis(u.second,v.first)>dd) res=mpr(u.second,v.first),dd=Gd(res);
if(Dis(u.second,v.second)>dd) res=mpr(u.second,v.second),dd=Gd(res);
if(o) d[o]=dd;return res;
}
void Build(int o,int l,int r){
if(l==r){ g[o]=mpr(l,l),d[o]=0;return; }
Build(lc,l,mid);Build(rc,mid+1,r);
g[o]=PushUp(g[lc],g[rc],d[lc],d[rc],o);
}
pr Query(int o,int l,int r,int L,int R){
if(L<=l && r<=R) return g[o];
pr res=mpr(L,L);
if(L<=mid) res=Query(lc,l,mid,L,R);
if(R>mid) res=PushUp(res,Query(rc,mid+1,r,L,R));
return res;
}
pr Merge(pr u,pr v){
pr res=mpr(u.first,v.first);int d=Gd(res);
if(Dis(u.first,v.second)>d) res=mpr(u.first,v.second),d=Gd(res);
if(Dis(u.second,v.first)>d) res=mpr(u.second,v.first),d=Gd(res);
if(Dis(u.second,v.second)>d) res=mpr(u.second,v.second),d=Gd(res);
return res;
}
int Query(int a,int b,int c,int d){
pr r1=Query(1,1,n,a,b),r2=Query(1,1,n,c,d),r3=Merge(r1,r2);
return Gd(r3);
}
#undef lc
#undef rc
#undef mid
#undef Gd
}seg;
int main(){
n=in();memset(d,0x3f,sizeof(d));
for(int i=1,u,v,w;i<n;i++) u=in(),v=in(),w=in(),g[u].push_back(mpr(v,w)),g[v].push_back(mpr(u,w));
DFS(1,1,1,0),init(),seg.Build(1,1,n);
for(int k=in(),a,b,c,d;k--;){
a=in(),b=in(),c=in(),d=in();
printf("%d\n",seg.Query(a,b,c,d));
}return 0;
}
51Nod 1766 树上的最远点对的更多相关文章
- 51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径
51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径 题面 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即 ...
- [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)
[51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...
- 51nod 1766 树上的最远点对——线段树
n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j& ...
- 51nod 1766 树上的最远点对(线段树)
像树的直径一样,两个集合的最长路也是由两个集合内部的最长路的两个端点组成的,于是我们知道了两个集合的最长路,枚举一下两两端点算出答案就可以合并了,所以就可以用线段树维护一个区间里的最长路了. #inc ...
- 【树形结构】51nod 1766 树上的最远点对
题目内容 \(n\)个点被\(n−1\)条边连接成了一颗树,边有权值\(w_i\).有\(q\)个询问,给出\([a,b]\)和\([c,d]\)两个区间,表示点的标号请你求出两个区间内各选一点之间的 ...
- 51 nod 1766 树上的最远点对(线段树+lca)
1766 树上的最远点对 基准时间限制:3 秒 空间限制:524288 KB 分值: 80 难度:5级算法题 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个 ...
- 【51nod】1766 树上的最远点对
[题意]给定n个点的树,m次求[a,b]和[c,d]中各选出一个点的最大距离.abcd是标号区间,n,m<=10^5 [算法]LCA+树的直径理论+线段树 [题解] 树的直径性质:距离树上任意点 ...
- 51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)
题目链接 \(Description\) 给定一棵树.每次询问给定\(a\sim b,c\sim d\)两个下标区间,从这两个区间中各取一个点,使得这两个点距离最远.输出最远距离. \(n,q\leq ...
- 51Nod1766 树上的最远点对
1766 树上的最远点对 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i&l ...
随机推荐
- 中缀表达式转后缀表达式(用于求字符串表达式值)(js栈和队列的实现是通过数组的push和unshift方法插值,pop方法取值)
中缀表达式:就是我通常用的算术或逻辑公式: 后缀表达式:不包含括号,运算符放在两个运算对象后面,所有的计算按运算符出现的顺序,严格从左向右进行,不用考虑运算符优先级: 如,(2+1)*3 转换后,2 ...
- 云服务程序在启动的时候执行Powershell脚本
如果在云服务程序启动时候,需要执行Powershell脚本,我们需要将脚本嵌入到程序中,并且编写一个cmd来执行这个脚本,具体如下: 1.编写测试的Powershell脚本:每隔10分钟 检测dns ...
- Behavior Tree
http://www.craft.ai/blog/bt-101-behavior-trees-grammar-basics/ https://github.com/libgdx/gdx-ai/wiki ...
- FBX Software Development Kit
FBX Software Development Kit The FBX Software Development Kit (FBX SDK) allows software developers t ...
- array_filter移除空数组
$arr = array( "0"=> "564645", "1"=>"", "2"=& ...
- .NET对象判等归纳与总结
1.引言 最近在看<CLR via C#>看到对象判等的那一节,觉得这也是.NET基础知识中比较重要的部分就写一篇博文来简单的总结归纳一下. 2..NET下的对象判等 在.NET中关于对象 ...
- Android中Java与JavaScript之间交互(转)
Android代码: package com.fyfeng.testjavascript; import android.app.Activity; import android.content.In ...
- 使用emmet如何生成lipsum的随机内容
emmet不会解析(即扩展)大括号中的内容, 它只是把大括号中的内容当成纯粹的字符串, 当成 literal的文本, 不会当成lipsum的缩写, 不会进行扩展. 要扩展, 就必须把lorem, li ...
- windows下vmware10.0 安装centos7
centos7.0-1506, 1511, 是指2015年, 06月份, 11月份. 这是rhel ubuntu发布新版本的时间. centos7.0 只提供了64位的系统下载: x86_64: we ...
- logrotate关于日志轮询和分割
如果你的是源码包安装的服务,那么对于Linux服务器上的一些服务在运行当中产生的日志很重要,可以判断你的服务是否有异常等,但源码包安装的日志是没有日志的轮询或者说是切割能力的, 所以你就需要用到bas ...