bzoj2144 LCA+二分

来源:互联网 发布:linux能用sqlserver吗 编辑:程序博客网 时间:2024/05/23 02:02

传送门


这个题解很棒


1.有两种跳法

①从两边往里跳 (x,y,z)->(x,2*y-x,z)或(x,y,z)->(x,2*y-z,y) 

②从中间往外跳(y-x≠z-y)  (x,y,z)->(2*x-y,x,z)或(x,y,z)->(x,z,2*z-y)

2.无解?都跳到不能跳了(y-x==z-y)都不一样,那肯定不行啊

3.发现从起始位置到目标位置,和从目标位置到起始位置答案是一样的。从目标位置和起始位置一起开始跳则一定会有重合的点(不然就无解了),那么重合的点再跳也一定会跳到(y-x==z-y)的情况,那么这个就很像LCA了。把离最远祖先(y-x==z-y)最远的那个点先跳到和另一个点一样的深度,再二分答案跳(因为不一定要跳到最远祖先的那个点)

4.由于每次一定都是间隔小的跳,所以可以一次性把能跳的都处理出来,即设u=y-x,v=z-y则若u<v一次最多可以跳(v-1)/u步


#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;


#define INF 1000000000


struct Node
{
    int x,y,z;
void orzcy()
{
 scanf("%d%d%d",&x,&y,&z);
 if(x>y){int t=x;x=y;y=t;}
 if(x>z){int t=x;x=z;z=t;}
 if(y>z){int t=z;z=y;y=t;}
}
}st,ed,a,b;
int l1,l2,len;


bool pd(Node A,Node B){return A.x==B.x&&A.y==B.y&&A.z==B.z;}
int Min(int A,int B){return A<B?A:B;}


Node Get(Node k,int lef)
{
int pre=0;
for(len=0;lef;len+=pre)
{
 int u=k.y-k.x,v=k.z-k.y;
 if(u==v)return k;
 if(u<v)
 {
  pre=Min(lef,(v-1)/u);
  lef-=pre;k.x+=pre*u;k.y+=pre*u;
 }
 else
 {
  pre=Min(lef,(u-1)/v);
  lef-=pre;k.y-=pre*v;k.z-=pre*v;
 }
}
return k;
}


int main()
{
st.orzcy();ed.orzcy();
a=Get(st,INF);l1=len;
b=Get(ed,INF);l2=len;
if(!pd(a,b)){puts("NO");return 0;}
if(l1<l2){Node t1=st;st=ed;ed=t1;int t2=l1;l1=l2;l2=t2;}
st=Get(st,l1-l2);
int l=0,r=l2;
while(l<=r)
{
 int mid=(l+r)>>1;
 if(pd(Get(st,mid),Get(ed,mid)))r=mid-1;
 else l=mid+1;
}
printf("YES\n%d\n",(l<<1)+l1-l2);
return 0;
}

0 0