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

题面

给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值。\(N, Q≤100000\)

分析

看到区间,我们应该想到用线段树维护,区间[l,r]存储编号在[l,r]内的点组成的一棵树的直径端点和长度

考虑如何合并区间。设两个区间的直径分别为(a,b) (c,d),则新区间的直径端点肯定也是a,b,c,d中的一个。(证明显然),那么新区间的直径就是max(dist(a,b),dist(a,c),dist(a,d),dist(b,c),dist(b,d),dist(c,d))

那么直接线段树维护就行了,pushup的时候按上面的那样合并。最后查询得到[l1,r1]内的直径(a,b),[l2,r2]内的直径(c,d) ,答案就是max(dist(a,c),dist(b,d),dist(b,c),dist(a,d))

如果用树上倍增求lca,时间复杂度为\(O(n\log^2n)\),改用dfs序+ST表求lca,查询只需要在ST表中求最值,是O(1)的,时间复杂度\(O(n\log n)\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100000
#define maxlogn 25
using namespace std;
inline void qread(int &x) {
x=0;
int sign=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
}
inline void qprint(long long x) {
if(x<0) {
putchar('-');
qprint(-x);
} else if(x==0) {
putchar('0');
return;
} else {
if(x>=10) qprint(x/10);
putchar(x%10+'0');
}
} int n,m;
struct edge {
int from;
int to;
int next;
int len;
} E[maxn*2+5];
int head[maxn+5];
int esz=1;
void add_edge(int u,int v,int w) {
esz++;
E[esz].from=u;
E[esz].to=v;
E[esz].len=w;
E[esz].next=head[u];
head[u]=esz;
} int cnt=0;
long long dis[maxn+5];
int seq[maxn*2+5];
int first[maxn+5];
int deep[maxn*2+5];
void dfs(int x,int fa,int d) {
seq[++cnt]=x;
deep[cnt]=d;
first[x]=cnt;
for(int i=head[x]; i; i=E[i].next) {
int y=E[i].to;
if(y!=fa) {
dis[y]=dis[x]+E[i].len;
dfs(y,x,d+1);
seq[++cnt]=x;
deep[cnt]=d;
}
}
} struct ST {//ST表求lca
int log2[maxn*2+5];
int f[maxn*2+5][maxlogn+5];
void ini(int n) {
log2[0]=-1;
for(int i=1; i<=n; i++) log2[i]=log2[i>>1]+1;
for(int i=1; i<=n; i++) f[i][0]=i;
for(int j=1; (1<<j)<=n; j++) {
for(int i=1; i+(1<<j)-1<=n; i++) {
int x=f[i][j-1];
int y=f[i+(1<<(j-1))][j-1];
if(deep[x]<deep[y]) f[i][j]=x;
else f[i][j]=y;
}
}
}
int query(int l,int r) {
int k=log2[r-l+1];
int x=f[l][k];
int y=f[r-(1<<k)+1][k];
if(deep[x]<deep[y]) return x;
else return y;
}
} S;
inline int lca(int x,int y) {
x=first[x];
y=first[y];
if(x>y) swap(x,y);
return seq[S.query(x,y)];
}
inline long long dist(int x,int y) {
return dis[x]+dis[y]-2*dis[lca(x,y)];
} struct value {//直径的端点与长度
int u;
int v;
long long dis;
value() { }
value(int _u,int _v,int _dis) {
u=_u;
v=_v;
dis=_dis;
}
inline void cal(int x,int y) {
long long len=dist(x,y);
if(len>dis) {
dis=len;
u=x;
v=y;
}
}
friend value operator + (value p,value q) {//合并答案
if(p.u==0) return q;//注意一个为空的情况
if(q.u==0) return p;
int a=p.u,b=p.v,c=q.u,d=q.v;
value ans=value(0,0,0);
ans.cal(a,b);
ans.cal(a,c);
ans.cal(a,d);
ans.cal(b,c);
ans.cal(b,d);
ans.cal(c,d);
return ans;
}
}; struct segment_tree {
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
struct node {
int l;
int r;
value val;
} tree[maxn*4+5];
void push_up(int x) {
tree[x].val=tree[lson(x)].val+tree[rson(x)].val;//重载之后运算变得很简洁
}
void build(int l,int r,int pos) {
tree[pos].l=l;
tree[pos].r=r;
tree[pos].val=value(0,0,0);
if(l==r) {
tree[pos].val=value(l,l,0);
return;
}
int mid=(l+r)>>1;
build(l,mid,pos<<1);
build(mid+1,r,pos<<1|1);
push_up(pos);
}
value query(int L,int R,int pos) {
if(L<=tree[pos].l&&R>=tree[pos].r) {
return tree[pos].val;
}
int mid=(tree[pos].l+tree[pos].r)>>1;
value ans=value(0,0,0);
if(L<=mid) ans=ans+query(L,R,pos<<1);
if(R>mid) ans=ans+query(L,R,pos<<1|1);
return ans;
}
} T; int main() {
int u,v,w;
int l1,r1,l2,r2;
qread(n);
for(int i=1; i<n; i++) {
qread(u);
qread(v);
qread(w);
add_edge(u,v,w);
add_edge(v,u,w);
}
dfs(1,0,1);
S.ini(cnt);
T.build(1,n,1); qread(m);
for(int i=1; i<=m; i++) {
qread(l1);
qread(r1);
qread(l2);
qread(r2);
value ans1=T.query(l1,r1,1);
value ans2=T.query(l2,r2,1);
//ans=ans1+ans2
int a=ans1.u,b=ans1.v,c=ans2.u,d=ans2.v;//这里不能只选ans1或ans2,所以不能写ans1+ans2
qprint(max(max(dist(a,c),dist(b,d)),max(dist(a,d),dist(b,c))));
putchar('\n');
}
}

[51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)的更多相关文章

  1. 51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径

    51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径 题面 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即 ...

  2. 51Nod 1766 树上的最远点对

    Description 一棵树,询问两个端点编号分别在在 \([a,b]\) 和 \([c,d]\) 两个区间中的最长链. Sol 线段树+ST表. 树上最长链可以合并,只需要合并两个区间最长链的两个 ...

  3. 51nod 1766 树上的最远点对——线段树

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

  4. 51nod 1766 树上的最远点对(线段树)

    像树的直径一样,两个集合的最长路也是由两个集合内部的最长路的两个端点组成的,于是我们知道了两个集合的最长路,枚举一下两两端点算出答案就可以合并了,所以就可以用线段树维护一个区间里的最长路了. #inc ...

  5. 【树形结构】51nod 1766 树上的最远点对

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

  6. 51 nod 1766 树上的最远点对(线段树+lca)

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

  7. 51nod 1206 Picture 矩形周长求并 | 线段树 扫描线

    51nod 1206 Picture 矩形周长求并 | 线段树 扫描线 #include <cstdio> #include <cmath> #include <cstr ...

  8. 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)

    Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...

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

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

随机推荐

  1. 什么是Azkaban?

    Azkaban是什么 Azkaban是由Linkedin开源的做批量工作流任务的调度器.在一个工作流内按照特定的顺序运行一组工作和流程.Azkaban定义了一种KV文件格式来建立任务之间的相互依赖关系 ...

  2. bzoj1875 [SDOI2009]HH去散步 矩阵快速幂

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1875 题解 如果没有这个"不能立刻沿着刚刚走来的路走回",那么这个题就是一 ...

  3. Thread类与Runnable接口

    Runnable 先看看源码中对Runnable的声明 @FunctionalInterface public interface Runnable { /** * When an object im ...

  4. 对http的研究

    HTTP 简介 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准. HTTP是一个基于 ...

  5. intraweb首次与LayUI结合

    intraweb可以说是Delphi Web开发的好帮手,但是自带的控件搭建页面,感觉不是那么美观,于是想引用一个UI框架,Delphi来提供后台访问,但是发现一个问题,如果intraweb用模版,L ...

  6. Hadoop 学习目录(搁置)

    简介 Hadoop是一个由Apache基金会所开发的分布式系统基础架构.用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群的威力进行高速运算和存储.Hadoop实现了一个分布式文件系 ...

  7. springboot整合hibernate案例

    1.运行环境 开发工具:intellij idea JDK版本:1.8 项目管理工具:Maven 4.0.0 2.GITHUB地址 https://github.com/nbfujx/springBo ...

  8. MS4W安装教程

    简介 欢迎使用MS4W,这是由Gateway Geomatics开发的快速简便的安装程序,用于为Windows及其附带应用程序(如Geomoose.MapBender.Openlayers等)设置Ma ...

  9. UPDATE 在不同数据库中的使用方式

    MYSQL 中update 表一 set Gmoney = 表二.列名 from 表一,表二 where 表一.EMPID = 表二.EMPID举例:update table1 set table1. ...

  10. Solr JAVA客户端SolrJ的使用

    一.Solrj简介 SolrJ是操作Solr的JAVA客户端,它提供了增加.修改.删除.查询Solr索引的JAVA接口.SolrJ针对 Solr提供了Rest 的HTTP接口进行了封装, SolrJ底 ...