首页 > 代码库 > hdu3830(lca + 二分)

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 }
View Code

 

hdu3830(lca + 二分)