1766 树上的最远点对

基准时间限制:3 秒 空间限制:524288 KB 分值: 80 难度:5级算法题
 
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
/*
51 nod 1766 树上的最远点对(线段树+lca) problem:
n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的
最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d} solve:
最开始想的是树链剖分,结果发现是区间[a,b]. 看成链了...
看题解说的是最远点有合并的性质. 就是[a,b]的最远点ta,tb和[b+1,c]的最远点tc,td这四个点中距离最远
的就是[a,c]的最远点.. 证明并没有怎么看懂- - 如果用线段树和并的话,需要快速求两点之间的距离. 可以用st快速求lca来解决,预处理便能得到O(1)的.
然后就是线段树合并时处理下. http://blog.csdn.net/rzo_kqp_orz/article/details/52280811 hhh-2016/09/15-21:16:26
*/
#pragma comment(linker,"/STACK:124000000,124000000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <math.h>
#include <queue>
#include <set>
#include <map>
#define lson i<<1
#define rson i<<1|1
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define scanfi(a) scanf("%d",&a)
#define scanfs(a) scanf("%s",a)
#define scanfl(a) scanf("%I64d",&a)
#define scanfd(a) scanf("%lf",&a)
#define key_val ch[ch[root][1]][0]
#define eps 1e-7
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const ll mod = 1e9+7;
const int MAXN = 100010;
const double PI = acos(-1.0); template<class T> void read(T&num)
{
char CH;
bool F=false;
for(CH=getchar(); CH<'0'||CH>'9'; F= CH=='-',CH=getchar());
for(num=0; CH>='0'&&CH<='9'; num=num*10+CH-'0',CH=getchar());
F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p)
{
if(!p)
{
puts("0");
return;
}
while(p) stk[++ tp] = p%10, p/=10;
while(tp) putchar(stk[tp--] + '0');
putchar('\n');
} int rmq[2*MAXN];
struct ST
{
int mm[2*MAXN];
int dp[2*MAXN][20];
void init(int n)
{
mm[0] = -1;
for(int i = 1; i <= n; i++)
{
mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
dp[i][0] = i;
}
for(int j = 1; j <= mm[n]; j++)
for(int i = 1; i + (1<<j) - 1 <= n; i++)
dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
}
int query(int a,int b)
{
if(a > b)swap(a,b);
int k = mm[b-a+1];
return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
}
}; struct Edge
{
int to,next;
ll w;
};
Edge edge[MAXN*2];
int tot,head[MAXN]; int F[MAXN*2];
int P[MAXN];
int cnt;
ll dis[MAXN];
ST st;
void ini()
{
tot = 0;
memset(head,-1,sizeof(head));
}
void add_edge(int u,int v,ll w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
void dfs(int u,int pre,int dep)
{
F[++cnt] = u;
rmq[cnt] = dep;
P[u] = cnt;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(v == pre)continue;
dis[v] = dis[u] + edge[i].w;
dfs(v,u,dep+1);
F[++cnt] = u;
rmq[cnt] = dep;
}
}
void LCA_init(int root,int node_num)
{
cnt = 0;
dfs(root,root,0);
st.init(2*node_num-1);
}
int query_lca(int u,int v)
{
return F[st.query(P[u],P[v])];
} ll distan(int a,int b)
{
int lca = query_lca(a,b);
return dis[a]+dis[b]-dis[lca]-dis[lca];
} struct node
{
int l,r;
int s,t;
ll len;
} tree[MAXN << 2]; void cal(int i,int a,int b)
{
ll len = distan(a,b);
if(tree[i].len < len)
{
tree[i].len = len;
tree[i].s = a;
tree[i].t = b;
}
} void push_up(int i)
{
cal(i,tree[lson].s,tree[rson].s);
cal(i,tree[lson].s,tree[rson].t);
cal(i,tree[lson].t,tree[rson].s);
cal(i,tree[lson].t,tree[rson].t); cal(i,tree[lson].s,tree[lson].t);
cal(i,tree[rson].s,tree[rson].t);
} void build(int i,int l,int r)
{
tree[i].l = l,tree[i].r = r;
tree[i].len = 0;
tree[i].s = tree[i].t = 0;
if(l == r)
{
tree[i].s = tree[i].t = l;
tree[i].len = 0;
return;
}
int mid = (tree[i].l + tree[i].r) >> 1;
build(lson,l,mid);
build(rson,mid+1,r);
push_up(i);
}
int from,to;
void solve(int a,int b,ll &len)
{
if(distan(a,b) > len)
{
len = distan(a,b);
from = a,to = b;
}
} void query(int i,int l,int r,int &ta,int &tb)
{
ta = tb = -1;
if(tree[i].l >= l && tree[i].r <= r)
{
ta = tree[i].s ;
tb = tree[i].t; return ;
}
int mid = (tree[i].l + tree[i].r) >> 1;
int ls,lt,rs,rt;
ls = lt = rs = rt= -1;
if(r <= mid)
query(lson,l,r,ta,tb);
else if(l > mid)
query(rson,l,r,ta,tb);
else
{
ll tans = -1;
query(lson,l,mid,ls,lt);
query(rson,mid+1,r,rs,rt);
solve(ls,rt,tans);
solve(ls,rs,tans);
solve(lt,rt,tans);
solve(lt,rs,tans);
solve(ls,lt,tans);
solve(rs,rt,tans);
ta = from ,tb = to;
}
push_up(i);
} int main()
{
// freopen("in.txt","r",stdin);
int n;
int u,v,w;
read(n);
ini();
for(int i = 1; i < n; i++)
{
read(u),read(v),read(w);
add_edge(u,v,w);
add_edge(v,u,w); }
dis[1] = 0;
LCA_init(1,n);
build(1,1,n); int a,b,m;
int max1,min1,max2,min2; read(m);
for(int i = 1; i <= m; i++)
{
ll ans = 0;
read(u),read(v);
read(a),read(b);
query(1,u,v,max1,min1);
query(1,a,b,max2,min2);
// cout << max1 << max2 << min1<<min2 <<endl;
ans = max(ans,distan(max1,max2));
ans = max(ans,distan(max1,min2));
ans = max(ans,distan(min1,max2));
ans = max(ans,distan(min1,min2));
printf("%I64d\n",ans);
}
return 0;
}

  

51 nod 1766 树上的最远点对(线段树+lca)的更多相关文章

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

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

  2. csu 1798(树上最远点对,线段树+lca)

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

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

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

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

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

  5. BZOJ 2588: Spoj 10628. Count on a tree-可持久化线段树+LCA(点权)(树上的操作) 无语(为什么我的LCA的板子不对)

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 9280  Solved: 2421 ...

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

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

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

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

  8. 51Nod1766 树上的最远点对 ST表 LCA 线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1766.html 题目传送门 - 51Nod1766 题意 n个点被n-1条边连接成了一颗树,给出a~ ...

  9. 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)

    线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...

随机推荐

  1. Beta集合

    Beta冲刺day1 Beta冲刺day2 Beta冲刺day3 Beta冲刺day4 Beta冲刺day5 Beta冲刺day6 Beta冲刺day7 测试总结 总结合集 Beta预备

  2. Environment.getExternalStorageDirectory()

    Environment.getExternalStorageDirectory()得到的是storage/emulated/0

  3. 从PRISM开始学WPF(二)Prism?

    目录: 从PRISM开始学WPF(一)WPF? 从PRISM开始学WPF(二)Prism? 从PRISM开始学WPF(三)Prism-Region? 从PRISM开始学WPF(四)Prism-Modu ...

  4. nyoj 阶乘0

    阶乘的0 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 计算n!的十进制表示最后有多少个0   输入 第一行输入一个整数N表示测试数据的组数(1<=N< ...

  5. 第二章 初识JSP

    第二章   初识JSP 一.JSP简述 1.是JSP JSP是指在HTML中嵌入Java脚本语言.全称(Java Server Pages) 当用户通过浏览器访问Web应用时,使用JSP容器对请求的J ...

  6. 从PRISM开始学WPF(八)導航Navigation?

    0x6Navigation Basic Navigation Prism中的Navigation提供了一种类似导航的功能,他可以根据用户的输入,来刷新UI. 先看一个最简单的例子,通过按钮来导航到一个 ...

  7. mongodb 索引的基本命令

    mongodb的索引: 在数据量超大的时候,能够极大的增快查询速率,但是会降低更新效率.建立索引: db.集合.ensureIndex({属性:1}) //1代表升序 -1代表降序 db.集合.ens ...

  8. [洛谷P2024/POJ1182]食物链 - 带偏移量的并查集(2)

    Description 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的 ...

  9. Linux:crontab组件部署linux定时任务

    crontab简介 crond 是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务 工具,并且会自动启动c ...

  10. 通过java api统计hive库下的所有表的文件个数、文件大小

    更新hadoop fs 命令实现: [ss@db csv]$ hadoop fs -count /my_rc/my_hive_db/* 18/01/14 15:40:19 INFO hdfs.Peer ...