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
  1. 第一行一个数字 n n<=100000
  2. 第二行到第n行每行三个数字描述路的情况, x,y,(1<=x,y<=n,1<=z<=10000)表示xy之间有一条长度为z的路。
  3. n+1行一个数字m,表示询问次数 m<=100000
  4. 接下来m行,每行四个数a,b,c,d
Output
  1. m行,表示每次询问的最远距离
Input示例
  1. 5
  2. 1 2 1
  3. 2 3 2
  4. 1 4 3
  5. 4 5 4
  6. 1
  7. 2 3 4 5
Output示例
  1. 10
  1. /*
  2. 51 nod 1766 树上的最远点对(线段树+lca)
  3.  
  4. problem:
  5. n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的
  6. 最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d}
  7.  
  8. solve:
  9. 最开始想的是树链剖分,结果发现是区间[a,b]. 看成链了...
  10. 看题解说的是最远点有合并的性质. 就是[a,b]的最远点ta,tb和[b+1,c]的最远点tc,td这四个点中距离最远
  11. 的就是[a,c]的最远点.. 证明并没有怎么看懂- -
  12.  
  13. 如果用线段树和并的话,需要快速求两点之间的距离. 可以用st快速求lca来解决,预处理便能得到O(1)的.
  14. 然后就是线段树合并时处理下.
  15.  
  16. http://blog.csdn.net/rzo_kqp_orz/article/details/52280811
  17.  
  18. hhh-2016/09/15-21:16:26
  19. */
  20. #pragma comment(linker,"/STACK:124000000,124000000")
  21. #include <algorithm>
  22. #include <iostream>
  23. #include <cstdlib>
  24. #include <cstdio>
  25. #include <cstring>
  26. #include <vector>
  27. #include <math.h>
  28. #include <queue>
  29. #include <set>
  30. #include <map>
  31. #define lson i<<1
  32. #define rson i<<1|1
  33. #define ll long long
  34. #define clr(a,b) memset(a,b,sizeof(a))
  35. #define scanfi(a) scanf("%d",&a)
  36. #define scanfs(a) scanf("%s",a)
  37. #define scanfl(a) scanf("%I64d",&a)
  38. #define scanfd(a) scanf("%lf",&a)
  39. #define key_val ch[ch[root][1]][0]
  40. #define eps 1e-7
  41. #define inf 0x3f3f3f3f3f3f3f3f
  42. using namespace std;
  43. const ll mod = 1e9+7;
  44. const int MAXN = 100010;
  45. const double PI = acos(-1.0);
  46.  
  47. template<class T> void read(T&num)
  48. {
  49. char CH;
  50. bool F=false;
  51. for(CH=getchar(); CH<'0'||CH>'9'; F= CH=='-',CH=getchar());
  52. for(num=0; CH>='0'&&CH<='9'; num=num*10+CH-'0',CH=getchar());
  53. F && (num=-num);
  54. }
  55. int stk[70], tp;
  56. template<class T> inline void print(T p)
  57. {
  58. if(!p)
  59. {
  60. puts("0");
  61. return;
  62. }
  63. while(p) stk[++ tp] = p%10, p/=10;
  64. while(tp) putchar(stk[tp--] + '0');
  65. putchar('\n');
  66. }
  67.  
  68. int rmq[2*MAXN];
  69. struct ST
  70. {
  71. int mm[2*MAXN];
  72. int dp[2*MAXN][20];
  73. void init(int n)
  74. {
  75. mm[0] = -1;
  76. for(int i = 1; i <= n; i++)
  77. {
  78. mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
  79. dp[i][0] = i;
  80. }
  81. for(int j = 1; j <= mm[n]; j++)
  82. for(int i = 1; i + (1<<j) - 1 <= n; i++)
  83. 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];
  84. }
  85. int query(int a,int b)
  86. {
  87. if(a > b)swap(a,b);
  88. int k = mm[b-a+1];
  89. return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
  90. }
  91. };
  92.  
  93. struct Edge
  94. {
  95. int to,next;
  96. ll w;
  97. };
  98. Edge edge[MAXN*2];
  99. int tot,head[MAXN];
  100.  
  101. int F[MAXN*2];
  102. int P[MAXN];
  103. int cnt;
  104. ll dis[MAXN];
  105. ST st;
  106. void ini()
  107. {
  108. tot = 0;
  109. memset(head,-1,sizeof(head));
  110. }
  111. void add_edge(int u,int v,ll w)
  112. {
  113. edge[tot].to = v;
  114. edge[tot].w = w;
  115. edge[tot].next = head[u];
  116. head[u] = tot++;
  117. }
  118. void dfs(int u,int pre,int dep)
  119. {
  120. F[++cnt] = u;
  121. rmq[cnt] = dep;
  122. P[u] = cnt;
  123. for(int i = head[u]; i != -1; i = edge[i].next)
  124. {
  125. int v = edge[i].to;
  126. if(v == pre)continue;
  127. dis[v] = dis[u] + edge[i].w;
  128. dfs(v,u,dep+1);
  129. F[++cnt] = u;
  130. rmq[cnt] = dep;
  131. }
  132. }
  133. void LCA_init(int root,int node_num)
  134. {
  135. cnt = 0;
  136. dfs(root,root,0);
  137. st.init(2*node_num-1);
  138. }
  139. int query_lca(int u,int v)
  140. {
  141. return F[st.query(P[u],P[v])];
  142. }
  143.  
  144. ll distan(int a,int b)
  145. {
  146. int lca = query_lca(a,b);
  147. return dis[a]+dis[b]-dis[lca]-dis[lca];
  148. }
  149.  
  150. struct node
  151. {
  152. int l,r;
  153. int s,t;
  154. ll len;
  155. } tree[MAXN << 2];
  156.  
  157. void cal(int i,int a,int b)
  158. {
  159. ll len = distan(a,b);
  160. if(tree[i].len < len)
  161. {
  162. tree[i].len = len;
  163. tree[i].s = a;
  164. tree[i].t = b;
  165. }
  166. }
  167.  
  168. void push_up(int i)
  169. {
  170. cal(i,tree[lson].s,tree[rson].s);
  171. cal(i,tree[lson].s,tree[rson].t);
  172. cal(i,tree[lson].t,tree[rson].s);
  173. cal(i,tree[lson].t,tree[rson].t);
  174.  
  175. cal(i,tree[lson].s,tree[lson].t);
  176. cal(i,tree[rson].s,tree[rson].t);
  177. }
  178.  
  179. void build(int i,int l,int r)
  180. {
  181. tree[i].l = l,tree[i].r = r;
  182. tree[i].len = 0;
  183. tree[i].s = tree[i].t = 0;
  184. if(l == r)
  185. {
  186. tree[i].s = tree[i].t = l;
  187. tree[i].len = 0;
  188. return;
  189. }
  190. int mid = (tree[i].l + tree[i].r) >> 1;
  191. build(lson,l,mid);
  192. build(rson,mid+1,r);
  193. push_up(i);
  194. }
  195. int from,to;
  196. void solve(int a,int b,ll &len)
  197. {
  198. if(distan(a,b) > len)
  199. {
  200. len = distan(a,b);
  201. from = a,to = b;
  202. }
  203. }
  204.  
  205. void query(int i,int l,int r,int &ta,int &tb)
  206. {
  207. ta = tb = -1;
  208. if(tree[i].l >= l && tree[i].r <= r)
  209. {
  210. ta = tree[i].s ;
  211. tb = tree[i].t;
  212.  
  213. return ;
  214. }
  215. int mid = (tree[i].l + tree[i].r) >> 1;
  216. int ls,lt,rs,rt;
  217. ls = lt = rs = rt= -1;
  218. if(r <= mid)
  219. query(lson,l,r,ta,tb);
  220. else if(l > mid)
  221. query(rson,l,r,ta,tb);
  222. else
  223. {
  224. ll tans = -1;
  225. query(lson,l,mid,ls,lt);
  226. query(rson,mid+1,r,rs,rt);
  227. solve(ls,rt,tans);
  228. solve(ls,rs,tans);
  229. solve(lt,rt,tans);
  230. solve(lt,rs,tans);
  231. solve(ls,lt,tans);
  232. solve(rs,rt,tans);
  233. ta = from ,tb = to;
  234. }
  235. push_up(i);
  236. }
  237.  
  238. int main()
  239. {
  240. // freopen("in.txt","r",stdin);
  241. int n;
  242. int u,v,w;
  243. read(n);
  244. ini();
  245. for(int i = 1; i < n; i++)
  246. {
  247. read(u),read(v),read(w);
  248. add_edge(u,v,w);
  249. add_edge(v,u,w);
  250.  
  251. }
  252. dis[1] = 0;
  253. LCA_init(1,n);
  254. build(1,1,n);
  255.  
  256. int a,b,m;
  257. int max1,min1,max2,min2;
  258.  
  259. read(m);
  260. for(int i = 1; i <= m; i++)
  261. {
  262. ll ans = 0;
  263. read(u),read(v);
  264. read(a),read(b);
  265. query(1,u,v,max1,min1);
  266. query(1,a,b,max2,min2);
  267. // cout << max1 << max2 << min1<<min2 <<endl;
  268. ans = max(ans,distan(max1,max2));
  269. ans = max(ans,distan(max1,min2));
  270. ans = max(ans,distan(min1,max2));
  271. ans = max(ans,distan(min1,min2));
  272. printf("%I64d\n",ans);
  273. }
  274. return 0;
  275. }

  

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. 设计模式NO.3

    设计模式NO.3 本次博客内容为第三次设计模式的练习.根据老师的要求完成下列题目: 题目1 某商品管理系统的商品名称存储在一个字符串数组中,现需要自定义一个双向迭代器(MyIterator)实现对该商 ...

  2. django的模板(二)

    模板(二) 实验简介 本节继续介绍模板的常用标签,for.if.ifequal和注释标签. 一.基本的模板标签和过滤器 1. 标签 if/else {% if %} 标签检查(evaluate)一个变 ...

  3. 小草手把手教你LabVIEW串口仪器控制—安装使用仪器现有驱动

    声明:很多仪器是没有驱动的.所以,具体问题具体分析.另外声明:所谓的驱动,也就是封装好的底层的串口通信程序,也是程序而已,只不过别人帮你做成了子 VI,让自己容易用.所以:不要弄混淆了概念.国外的很多 ...

  4. php后台的在控制器中就可以实现阅读数增加

    $smodel=M('Sswz');$smodel->where($map)->setInc('view' ,1);php后台的在控制器中就可以实现阅读数增加前台不需要传值

  5. Java看书学习笔记

    1.POM:maven ,项目管理工具存放Jar包的文件2.mybatis-generator-core-1.3.2 生成文件 生成语句: java -jar mybatis-generator-co ...

  6. Mysql主从复制架构实战

    [root@Mysql-master ~]# vim /etc/my.cnf log-bin=mysql-bin server-id = 1  #slave端server-id值改成2 mysql&g ...

  7. Mego开发文档 - 加载关系数据

    加载关系数据 Mego允许您使用模型中的导航属性来加载相关数据对象.目前只支持强制加载数据对象.只有正确配置了关系才能加载关系数据,相关内容可参考关系配置文档. 加载对象属性 您可以使用该Includ ...

  8. mosquitto安装和测试

    一.安装 1.windows安装 安装完毕,更新安装目录的dll文件 2.linux安装 编译保存用户数据到数据库的插件 安装 3.启动 mosquitto mosquitto mosquitto_p ...

  9. Python操作SQLAchemy

    如果对代码不懂就看这个:http://www.cnblogs.com/jixuege-1/p/6272888.html 本篇对于Python操作MySQL主要使用两种方式: 原生模块 pymsql O ...

  10. 初试valgrind内存调试工具

    虽然GDB调试工具功能强大,但对于平时做题调试的使用并不方便,这里尝试学习使用比较简单的valgrind工具 Valgrind是一个提供程序调试及性能分析的工具集.其包含的工具主要有Memcheck, ...