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

(PS 建议使用读入优化)
Input
第一行一个数字 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。
Output
共m行,表示每次询问的最远距离
Input示例
5
1 2 1
2 3 2
1 4 3
4 5 4
1
2 3 4 5
Output示例
10

————————————————————————————

这道题可以证明两个区间并起来的最远点对 一定是两个区间单独最远点对中的四个点

然后我们就可以利用线段树来维护辣

#include<cstdio>
#include<cstring>
#include<algorithm>
using std::swap;
const int M=2e5+,inf=0x3f3f3f3f;
int read(){
int ans=,f=,c=getchar();
while(c<''||c>''){if(c=='-') f=-; c=getchar();}
while(c>=''&&c<=''){ans=ans*+(c-''); c=getchar();}
return ans*f;
}
int max(int x,int y){return x>y?x:y;}
int n,m;
int first[M],cnt;
struct node{int to,next,w;}e[*M];
void ins(int a,int b,int w){e[++cnt]=(node){b,first[a],w}; first[a]=cnt;}
void insert(int a,int b,int w){ins(a,b,w); ins(b,a,w);}
int sz[M],son[M],dep[M],fa[M],top[M],id[M],idp=,dis[M];
void f1(int x){
sz[x]=;
for(int i=first[x];i;i=e[i].next){
int now=e[i].to;
if(now==fa[x]) continue;
fa[now]=x;
dep[now]=dep[x]+;
dis[now]=dis[x]+e[i].w;
f1(now); sz[x]+=sz[now];
if(sz[now]>sz[son[x]]) son[x]=now;
}
}
void f2(int x,int tp){
top[x]=tp; id[x]=idp++;
if(son[x]) f2(son[x],tp);
for(int i=first[x];i;i=e[i].next){
int now=e[i].to;
if(now!=fa[x]&&now!=son[x]) f2(now,now);
}
}
int cntq;
struct pos{int mx,p1,p2;}tr[*M+];
int find(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return x;
}
int calc(int x,int y){
int lca=find(x,y);
return dis[x]+dis[y]-*dis[lca];
}
void up(int x,int ls,int rs){
int k;
tr[x].mx=tr[ls].mx; tr[x].p1=tr[ls].p1; tr[x].p2=tr[ls].p2;
if(tr[rs].mx>=tr[x].mx) tr[x].mx=tr[rs].mx,tr[x].p1=tr[rs].p1,tr[x].p2=tr[rs].p2;
int x1=tr[ls].p1,y1=tr[ls].p2,x2=tr[rs].p1,y2=tr[rs].p2;
if(x1!=-){
if(x2!=-&&(k=calc(x1,x2))>=tr[x].mx) tr[x].mx=k,tr[x].p1=x1,tr[x].p2=x2;
if(y2!=-&&(k=calc(x1,y2))>=tr[x].mx) tr[x].mx=k,tr[x].p1=x1,tr[x].p2=y2;
}
if(y1!=-){
if(x2!=-&&(k=calc(y1,x2))>=tr[x].mx) tr[x].mx=k,tr[x].p1=x2,tr[x].p2=y1;
if(y2!=-&&(k=calc(y1,y2))>=tr[x].mx) tr[x].mx=k,tr[x].p1=y1,tr[x].p2=y2;
}
}
void build(int x,int l,int r){
if(l==r){
tr[x].p1=l; tr[x].p2=l;
tr[x].mx=; return ;
}
int mid=(l+r)>>;
build(x<<,l,mid);
build(x<<^,mid+,r);
up(x,x<<,x<<^);
}
int L,R;
int push_ans(int x,int l,int r){
if(L<=l&&r<=R) return x;
int mid=(l+r)>>,ly=++cntq;
tr[ly]=(pos){,-,-};
int s1=,s2=;
if(L<=mid) s1=push_ans(x<<,l,mid);
if(R>mid) s2=push_ans(x<<^,mid+,r);
up(ly,s1,s2);
return ly;
}
int ans,ly,a,b,c,d,s1,s2;
int main(){
int x,y,w;
n=read(); tr[].p1=tr[].p2=-; tr[].mx=-inf;
for(int i=;i<n;i++) x=read(),y=read(),w=read(),insert(x,y,w);
f1(); f2(,); build(,,n);
m=read();
for(int i=;i<=m;i++){
a=read(); b=read();
c=read(); d=read();
cntq=*M;
L=a; R=b; int s1=push_ans(,,n);
L=c; R=d; int s2=push_ans(,,n);
int x1=tr[s1].p1,y1=tr[s1].p2; //printf("[%d %d]\n",x1,y1);
int x2=tr[s2].p1,y2=tr[s2].p2; //printf("[%d %d]\n",x2,y2);
ans=max(max(calc(x1,y2),calc(x1,x2)),max(calc(y1,y2),calc(y1,x2)));
printf("%d\n",ans);
}
return ; }

51nod 1766 树上的最远点对——线段树的更多相关文章

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

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

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

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

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

    [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...

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

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

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

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

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

    题目内容 \(n\)个点被\(n−1\)条边连接成了一颗树,边有权值\(w_i\).有\(q\)个询问,给出\([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. csu 1798(树上最远点对,线段树+lca)

    1798: 小Z的城市 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 60  Solved: 16[Submit][Status][Web Board] ...

随机推荐

  1. C#窗口文件双击打开时出错

    出错原因: 1. 修改了该窗口文件的.Designer.cs文件中:#region Windows 窗体设计器生成的代码这里面的代码,导致运行不正常. 为了传递数据,我在构造函数中增加了传递的值. 需 ...

  2. BZOJ 1149 风铃(树形DP)

    题目描述的实际是一颗二叉树,对于每个结点,要么满叉,要么无叉. 对于一种无解的简单情况,我们搜一遍树找到最浅的叶子结点1和最深的叶子结点2,如果dep[1]<dep[2]-1,则显然无解. 所以 ...

  3. 【bzoj1688】[USACO2005 Open]Disease Manangement 疾病管理 状态压缩dp+背包dp

    题目描述 Alas! A set of D (1 <= D <= 15) diseases (numbered 1..D) is running through the farm. Far ...

  4. BZOJ4028 HEOI2015公约数数列(分块)

    前缀gcd的变化次数是log的,考虑对每一种gcd查询,问题变为查询一段区间是否存在异或前缀和=x/gcd. 无修改的话显然可以可持久化trie,但这玩意实在没法支持修改.于是考虑分块. 对于每一块将 ...

  5. 转:Scipy入门

    Scipy入门 转:http://notes.yeshiwei.com/scipy/getting_started.html 本章节主要内容来自 Getting Started .翻译的其中一部分,并 ...

  6. 【原创】宿主机远程登录虚拟机(windows server 2003系统)

    转载请注明,谢谢合作 1.虚拟机网络设置为  “桥接模式”如图 2.系统装好并登陆后 右键点击我的电脑,点击属性,然后在弹出来的选择框中勾选远程桌面-->启用这台计算机的远程桌面 然后点添加-- ...

  7. [洛谷P4962]朋也与光玉

    题目大意:有一张$n(n\leqslant100)$个点$m(m\leqslant n(n-1)$条边的有向图,每个点有一个颜色,需要找到一条长度为$k(k\leqslant13)$,恰好经过全部$k ...

  8. [Leetcode] minimum window substring 最小字符窗口

    Given a string S and a string T, find the minimum window in S which will contain all the characters ...

  9. BZOJ1597 土地购买 【dp + 斜率优化】

    1597: [Usaco2008 Mar]土地购买 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 5466  Solved: 2035 [Submi ...

  10. 洛谷 P3960 列队 解题报告

    P3960 列队 题目描述 \(Sylvia\)是一个热爱学习的女♂孩子. 前段时间,\(Sylvia\)参加了学校的军训.众所周知,军训的时候需要站方阵. \(Sylvia\)所在的方阵中有\(n ...