三点两两LCA性质定理的证明
严谨证明一个常识性的东西
主要是看大家做P4281时貌似并没有想到怎这么做,或是直接看了题解然后“感性理解”了
定理本身:
1.树上三个点的LCA不可能两两互异
即 不可能成立
2.这两个相同的的点以外的那点到三个点距离和最小 (其中三个点lca相同时另作讨论)
证:
引理1:如果a,b两个点在同一条末端在叶子节点上的链上,那么对于 ,必有
引理2:
令三个不全重合的点为a,b,c
不妨先对a,b,进行讨论
不妨设deep[a]>=deep[b]
1 a和b重合 那么 所以
2° a是b的后代 那么
C的存在有4种情况,如图
① C在s1 (a的下方) 此时
② C在s2 (ab之间) 同理 此时
③ C在s3(ab上方)此时
④C在s4(另一棵子树)
因为a和b在同条链上 那么和必相同(引理),即上图根结点.
3°a和b在两棵不同子树上 那么C的存在有5种情况(除去一种完全等价)
①C在s1 这种情况本质就是2°④
和相同(引理),为图中的m
②这个真的是同理 (引理)
③在s3区域内 那么a,b中必有一个点不与c在一条链上那么这个点和c,另一点的lca一定相同(引理)
④在s4区域内那么c一定是a,b的公共祖先
⑤在s5区域内 那么一定为n即a所在子树与子树s5的共同父亲
同理
证毕
性质2
“翻译一下就是那么就是离a,b,c距离之和最小点。
中得到了是a,b,c三条路径的交汇点,(想象一下把这个点"提住"作为根)
那么假设这个点向朝a/b/c的简单路径移动w 那么
那这个点朝着其他方向移动w那么 dis=(da+w)+(db+w)+(dc+w)=dis+3w >dis$
#include<bits/stdc++.h>
#define int long long
#define rg register
#define __max(aaa,bbb,ccc) max(max(aaa,bbb),ccc)
#define __min(aaa,bbb,ccc) min(min(aaa,bbb),ccc)
using namespace std;
const int N=5e5+5;
template <typename T> inline void read(T &x)
{
x=0;int f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x*=f;
}
template <typename T> inline void print(T x)
{
if(x>9) print(x/10);
putchar(x%10+48);
}
int n,jump[N][22],deep[N],m,s;
vector<int> vct[N];
void add(int x,int y)
{
vct[x].push_back(y);
vct[y].push_back(x);
}
void dfa(int now ,int from)
{
deep[now]=deep[from]+1;
jump[now][0]=from;
for(int j=1;j<=19;++j)
jump[now][j]=jump[jump[now][j-1]][j-1];//往上跳2^j==往上跳2^(j-1) 从这个点再往上2^(j-1)
for(int i=0;i<vct[now].size();++i)
{
int to=vct[now][i];
if(to==from)continue;
dfa(to,now);
}
return ;
}
int LCA(int x,int y)
{
if(deep[x]<deep[y])swap(x,y);//x is deeper than y
// for(;deep[x]>=deep[y];x=jump[x][(int)log2(deep[y]-deep[x]+1)]);
for(int i=19;i>=0;--i)
if(deep[jump[x][i]]>=deep[y])
x=jump[x][i];
// cout<<"x:" <<x<<"y:"<<y<<endl;
//统一深度
if(x==y)return x;
for(int i=19;i>=0;--i)//从后往前“二分”
{
if(jump[x][i]!=jump[y][i])
x=jump[x][i],
y=jump[y][i];
}
return jump[x][0];
//return x;
}
signed main()
{
cin>>n>>m;
s=1;deep[s]=1;
int x,y,z;
for(int i=1;i<n;++i)
{
read(x);
read(y);
add(x,y);
}
dfa(s,0);
for(int i=1;i<=m;++i)
{
read(x);
read(y);
read(z);
int l1=LCA(x,y);
int l2=LCA(x,z);
int l3=LCA(y,z);
int ans;
// printf("%lld %lld %lld\n",l1,l2,l3);
if(l1==l2) ans=l3;else
if(l2==l3) ans=l1;else
if(l3==l1) ans=l2;
cout<<ans<<' '<<deep[x]+deep[y]+deep[z]-deep[l1]-deep[l2]-deep[l3]<<endl;
}
}
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17971019,谢谢你的阅读或转载!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步