51Nod1766 树上的最远点对
1766 树上的最远点对
n个点被n-1条边连接成了一颗树,给出ab和cd两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d}
(PS 建议使用读入优化)
输入
第一行一个数字 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。
输出
共m行,表示每次询问的最远距离
输入样例
5
1 2 1
2 3 2
1 4 3
4 5 4
1
2 3 4 5
输出样例
10
题解
对于这个问题,我们不负责任的猜想一个性质。
对于l<k<r,编号在(l,r)之间的最远点对一定是编号在(l,k)的最远点对(a,b)和编号(k+1,r)的最远点对(c,d)四个端点组合成的六组点对:
(a,b)或(a,c)或(a,d)或(b,c)或(b,d)或(c,d)。
上述性质可以通过画图体会。
给一个不能再丑的图。
(画师:业界著名算法选手Claris)

S和T是直径 x是另一个点 如果另一棵树的某个点 在S那个区域 那么因为a<=b 所以它走T就好了 然后这个点在T区域也是同理的 如果那个点是一号点 或者二号点也是同理 如果在3就可以走到S……然后这个过程是可以用线段树合并维护下的。
那么区间之间的最远点对就可以由两个它的子区间合并得到,可以使用线段树来维护O(nlogn)预处理,O(1)查询。
所以我们可以求出编号(a,b)之间的最远点对,编号(c,d)之间的最远点对,然后相互计算下距离即可。总复杂度O(nlogn)
这题除了结论有点意思(并且这官方题解里面也没哟证明!)之外,就没有什么意思了。
线段树+ST表.
树上最长链可以合并,只需要合并两个区间最长链的两个端点即可.
ST表要预处理好 log ,用了cmath 的 log2() ,T的飞起.
这样复杂度就是 O(nlogn)
#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;
}
51Nod1766 树上的最远点对的更多相关文章
- 51Nod1766 树上的最远点对 ST表 LCA 线段树
		原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1766.html 题目传送门 - 51Nod1766 题意 n个点被n-1条边连接成了一颗树,给出a~ ... 
- 【做题】51Nod1766树上的最远点对——直径&线段树
		原文链接 https://www.cnblogs.com/cly-none/p/9890837.html 题意:给出一棵大小为\(n\)的树,边有边权.\(m\)次询问,每次给出两个标号区间\([a, ... 
- 51 nod 1766 树上的最远点对(线段树+lca)
		1766 树上的最远点对 基准时间限制:3 秒 空间限制:524288 KB 分值: 80 难度:5级算法题 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个 ... 
- 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]内的所有点对距离最大值.\ ... 
- 【51NOD1766】树上的最远点对(线段树,LCA,RMQ)
		题意:n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间, 表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c< ... 
- 【51nod】1766 树上的最远点对
		[题意]给定n个点的树,m次求[a,b]和[c,d]中各选出一个点的最大距离.abcd是标号区间,n,m<=10^5 [算法]LCA+树的直径理论+线段树 [题解] 树的直径性质:距离树上任意点 ... 
- 51Nod 1766 树上的最远点对
		Description 一棵树,询问两个端点编号分别在在 \([a,b]\) 和 \([c,d]\) 两个区间中的最长链. Sol 线段树+ST表. 树上最长链可以合并,只需要合并两个区间最长链的两个 ... 
- 51nod 1766 树上的最远点对——线段树
		n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j& ... 
随机推荐
- 【BZOJ4548】小奇的糖果 set(链表)+树状数组
			[BZOJ4548]小奇的糖果 Description 有 N 个彩色糖果在平面上.小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果.求出最多能够拾起多少糖果,使得获得的糖果并不包含所有的 ... 
- 打广告:B站广告
			https://www.bilibili.com/video/av52230444/ https://www.bilibili.com/video/av52230444/ https://www.bi ... 
- Cordova-安装Cordova过程详细解
			官方网站Apache Cordova 前提是你电脑上 1:全局安装了Node 2:全局安装了npm 3:安装了java,并配置好环境 4:下载安装好android-sdk,并配好环境,注意安卓虚拟机可 ... 
- 改善程序与设计的55个具体做法 day6
			条款13:以对象管理资源 资源,包括但不限于内存.句柄.GDI对象.数据库连接等. 内存要记得释放,句柄要记得closehandle, GDI对象要记得删除,数据库连接要记得关闭,等等等等. 以对象来 ... 
- ruby on rails 生产环境调试项目日志查看
			1.项目目录:log/production.log 2.nginx日志:/opt/nginx/logs 生产环境下做的任何更改都要重启服务器 重启 sudo kill $(cat /opt/nginx ... 
- Python OOP(2)-static method,class method and instance method
			静态方法(Static Method): 一种简单函数,符合以下要求: 1.嵌套在类中. 2.没有self参数. 特点: 1.类调用.实例调用,静态方法都不会接受自动的self参数. 2.会记录所有实 ... 
- 数据库基本表创建 完整性约束 foreign Key
			理解以下几张表的内容,根据实际情况设计属性名.数据类型.及各种完整性约束(primary key.foreign key.not null.unique.check),用数据定义语言实现,然后设计实验 ... 
- Ansible 实战之部署Web架构
			WEB架构(ubuntu 16.04): Proxy -- WebServer(Nginx+PHP+Django) -- Nosql -- MariaDB 一. 定义Inventory [proxy] ... 
- ubuntu 部署的mysql无法远程链接
			允许远程用户登录访问mysql的方法 从任何主机上使用root用户,密码:youpassword(你的root密码)连接到mysql服务器: # mysql -u root -proot mysql& ... 
- systemd基本使用
			参考金步国翻译的systemd中文手册: http://www.jinbuguo.com/systemd/index.html 金步国翻译质量都很高, 非常适合做参考 原文:https://wiki. ... 
