51 nod 1766 树上的最远点对(线段树+lca)
1766 树上的最远点对
- 第一行一个数字 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
- /*
- 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)的更多相关文章
- 51nod 1766 树上的最远点对——线段树
n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j& ...
- csu 1798(树上最远点对,线段树+lca)
1798: 小Z的城市 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 60 Solved: 16[Submit][Status][Web Board] ...
- 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]内的所有点对距离最大值.\ ...
- 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 ...
- 【51nod】1766 树上的最远点对
[题意]给定n个点的树,m次求[a,b]和[c,d]中各选出一个点的最大距离.abcd是标号区间,n,m<=10^5 [算法]LCA+树的直径理论+线段树 [题解] 树的直径性质:距离树上任意点 ...
- 51Nod 1766 树上的最远点对
Description 一棵树,询问两个端点编号分别在在 \([a,b]\) 和 \([c,d]\) 两个区间中的最长链. Sol 线段树+ST表. 树上最长链可以合并,只需要合并两个区间最长链的两个 ...
- 51Nod1766 树上的最远点对 ST表 LCA 线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1766.html 题目传送门 - 51Nod1766 题意 n个点被n-1条边连接成了一颗树,给出a~ ...
- 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)
线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...
随机推荐
- 设计模式NO.3
设计模式NO.3 本次博客内容为第三次设计模式的练习.根据老师的要求完成下列题目: 题目1 某商品管理系统的商品名称存储在一个字符串数组中,现需要自定义一个双向迭代器(MyIterator)实现对该商 ...
- django的模板(二)
模板(二) 实验简介 本节继续介绍模板的常用标签,for.if.ifequal和注释标签. 一.基本的模板标签和过滤器 1. 标签 if/else {% if %} 标签检查(evaluate)一个变 ...
- 小草手把手教你LabVIEW串口仪器控制—安装使用仪器现有驱动
声明:很多仪器是没有驱动的.所以,具体问题具体分析.另外声明:所谓的驱动,也就是封装好的底层的串口通信程序,也是程序而已,只不过别人帮你做成了子 VI,让自己容易用.所以:不要弄混淆了概念.国外的很多 ...
- php后台的在控制器中就可以实现阅读数增加
$smodel=M('Sswz');$smodel->where($map)->setInc('view' ,1);php后台的在控制器中就可以实现阅读数增加前台不需要传值
- Java看书学习笔记
1.POM:maven ,项目管理工具存放Jar包的文件2.mybatis-generator-core-1.3.2 生成文件 生成语句: java -jar mybatis-generator-co ...
- Mysql主从复制架构实战
[root@Mysql-master ~]# vim /etc/my.cnf log-bin=mysql-bin server-id = 1 #slave端server-id值改成2 mysql&g ...
- Mego开发文档 - 加载关系数据
加载关系数据 Mego允许您使用模型中的导航属性来加载相关数据对象.目前只支持强制加载数据对象.只有正确配置了关系才能加载关系数据,相关内容可参考关系配置文档. 加载对象属性 您可以使用该Includ ...
- mosquitto安装和测试
一.安装 1.windows安装 安装完毕,更新安装目录的dll文件 2.linux安装 编译保存用户数据到数据库的插件 安装 3.启动 mosquitto mosquitto mosquitto_p ...
- Python操作SQLAchemy
如果对代码不懂就看这个:http://www.cnblogs.com/jixuege-1/p/6272888.html 本篇对于Python操作MySQL主要使用两种方式: 原生模块 pymsql O ...
- 初试valgrind内存调试工具
虽然GDB调试工具功能强大,但对于平时做题调试的使用并不方便,这里尝试学习使用比较简单的valgrind工具 Valgrind是一个提供程序调试及性能分析的工具集.其包含的工具主要有Memcheck, ...