hdu3830(lca + 二分)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3830

题意: 有三个点 a, b, c, 对于其中任意一点 x 可以跨过一个点移动到另一个位置, 当且仅当移动前后的 x 与其所跨越的点的距离相等 .给出两组点, 问其能否相互到达, 若能并输出最少需要移动多少步 .

思路: http://www.cnblogs.com/scau20110726/archive/2013/06/14/3135024.html

代码:

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <algorithm>
  4 #define ll long long
  5 using namespace std;
  6
  7 struct node{
  8     ll x, y, z, d;
  9 };
 10
 11 void f(node &s){
 12     ll cnt[3];
 13     cnt[0] = s.x;
 14     cnt[1] = s.y;
 15     cnt[2] = s.z;
 16     sort(cnt, cnt + 3);
 17     s.x = cnt[0];
 18     s.y = cnt[1];
 19     s.z = cnt[2];
 20 }
 21
 22 bool equal(node a, node b){//判断两个节点是否想等
 23     if(a.x == b.x && a.y == b.y && a.z == b.z) return true;
 24     return false;
 25 }
 26
 27 node get_root(node &root){//这里要记录一下深度
 28     ll r;
 29     node cnt = root;
 30     ll p = cnt.y - cnt.x;
 31     ll q = cnt.z - cnt.y;
 32     while(p != q){
 33         if(q > p){ //右边大于左边
 34             r = (q - 1) / p;
 35             cnt.x += r * p;
 36             cnt.y += r * p;
 37         }else{
 38             r = (p - 1) / q;
 39             cnt.z -= r * q;
 40             cnt.y -= r * q;
 41         }
 42         root.d += r;
 43         f(cnt); //注意每个节点都要维护
 44         p = cnt.y - cnt.x;
 45         q = cnt.z - cnt.y;
 46     }
 47     return cnt;
 48 }
 49
 50 node get_pre(node cnt, ll step){ //返回cnt向上移动step步后到达的位置
 51     ll p, q, r;
 52     while(step > 0){
 53         p = cnt.y - cnt.x;
 54         q = cnt.z - cnt.y;
 55         if(q > p){
 56             r = (q - 1) / p;
 57             if(r > step) r = step;//注意剩余步数不足的情况
 58             cnt.x += r * p;
 59             cnt.y += r * p;
 60         }else{
 61             r = (p - 1) / q;
 62             if(r > step) r = step;
 63             cnt.z -= r * q;
 64             cnt.y -= r * q;
 65         }
 66         step -= r;
 67         f(cnt);
 68     }
 69     return cnt;
 70 }
 71
 72 ll solve(node s, node e){
 73     ll l = 0, r = s.d < e.d ? s.d : e.d;
 74     ll cnt = r;
 75     while(l <= r){
 76         ll mid = (l + r) >> 1;
 77         ll gg = cnt - mid;// mid 为 lca 位置, gg 为移动步数
 78         if(equal(get_pre(s, gg), get_pre(e, gg))) l = mid + 1;
 79         else r = mid - 1;
 80     }
 81     return ((cnt - (l - 1)) << 1);// l - 1 为lca位置
 82 }
 83
 84 int main(void){
 85     node s, e;
 86     while(~scanf("%lld%lld%lld%lld%lld%lld", &s.x, &s.y, &s.z, &e.x, &e.y, &e.z)){
 87         s.d = e.d = 0;
 88         f(s);
 89         f(e);
 90         if(!equal(get_root(s), get_root(e))){ //根节点不同无法到达
 91             puts("NO");
 92             continue;
 93         }
 94         ll d = abs(s.d - e.d);
 95         if(s.d > e.d) s = get_pre(s, d); //使两者处于同一深度
 96         else e = get_pre(e, d);
 97         int sol = solve(s, e);
 98         puts("YES");
 99         printf("%lld\n", d + sol);
100     }
101     return 0;
102 }

时间: 2024-08-05 22:48:12

hdu3830(lca + 二分)的相关文章

LCA + 二分

两个最近的点u和v的最近的公共的祖先称为最近公共祖先(LCA).普通的LCA算法,每算一次LCA的时间复杂度为线性o(n); 这里讲LCA + 二分的方法.首先对于任意的节点v,利用其父节点的信息,可以通过par2[v]=par[par[v]]得到向上走两步的节点.依此信息可以通过par4[v]=par2[par2[v]]得到向上走4步的节点.所以,根据此方法可以得到向上走2^k所得到的节点par[k][v].每次搜索的复杂度为o(log n),预处理par[k][v]的复杂度为o(nlog n

noip 2015 运输计划 (lca+二分)

/* 95 最后一个点T了 qian lv ji qiong 了 没学过树剖 听chx听xzc说的神奇的方法 Orz 首先求出每个计划的路径长度 这里写的倍增 然后二分答案 对于每个ans 统计>他的路径条数 tot 并维护最大差值 dec 并且对于每条不合法的路径维护每个点的经过次数 然后枚举点 如果经过次数==tot说明每一条不合法的都经过他 然后尝试把它建成虫洞 如果他对应边的权值>=dec 那么我们删掉它ans就合法了 关键是统计每个点在非法路径中的经过次数 : 维护sum数组 对于每

[NOIP2015]运输计划 D2 T3 LCA+二分答案+差分数组

[NOIP2015]运输计划 D2 T3 Description 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有星球. 小P掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从ui号星球沿最快的宇航路径飞行到vi号星球去.显然,飞船驶过一条航道是需要时间的,对于航道j,任意飞船驶过它所花费的时间为tj,并且任意两艘飞船之间不会产生任何干扰. 为了鼓励科技创新,L国国王同意小P的物流

二分算法~~~大综合

二分:一个非常神奇的算法:永远记住二分,分的是答案,直接在答案在的区间范围中二分,分出一个值,就判断是不是           答案,并进行转移 二分答案: 如果已知候选答案的范围[min,max],有时候我们不必通过计算得到答案,只需在此范围内应用“二分”的过程,逐渐靠近答案(最后,得到答案)! 一.何时可以使用“二分答案” 不是任何题目都适合使用“二分答案”的,我Sam观察到一般有以下的一些特征: A. 候选答案必须是离散的 ,且已知答案的范围是:[最小值min, 最大值max] (连续区间

NOIP 2015 BZOJ 4326 运输计划 (树链剖分+二分)

题目大意:给一棵带有边权的树,有m条路径,可以使一条边的权值为0,求最远路径的最小值.题解:因为题目的数据点给的很明确 因此可以打n*n的去骗前五十分.另外m=1时可以特判另外打个程序骗60分.60分程序: #include<cstdio> #include<algorithm> int dep[100001],fa[100001],last[200001],next[200001],e[200001],val[200001],cost[100001],tot,a,b,vv,u[1

[填坑][主线任务]历年NOIP刷题计划

今天又是喜闻乐见的非考试日,那么今天做点什么呢== 前些日子的主线任务陆陆续续(接近)完成了,好多蒙蔽的没学好的算法都算是入门补坑了 我听学长说,做题的顺序是:NOIP真题->NOIP模拟题->专项练习->杂题 啊哈!最重要的真题我还没做几道呢...于是这两天填填这个坑吧 [NOIP2016 Day1 T2]天天爱跑步 NOIP2016最难的题没有之一QAQ,原来做过一直没过,今天重新听讲解,总算打了出来 [NOIP2015 Day2 T3]运输计划 压轴题防AK,最后一个点及其凶残,并

hdu3830 (二分+LCA)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Checkers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 125536/65536 K (Java/Others)Total Submission(s): 775    Accepted Submission(s): 228 Problem Description Little X, Little Y and

BZOJ 4326:NOIP2015 运输计划(二分+差分+lca)

NOIP2015 运输计划Description公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去.显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰.为了鼓励科技创新, L

NOIP2015 运输计划(二分+LCA+差分)

4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 308  Solved: 208[Submit][Status][Discuss] Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui