- 1、本文档共6页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
解题思路
问题分析
给定一棵树和两个节点,需要找到这两个节点的最低公共祖先。树上的最低公共祖先是一个经典的问题,如果我们能够在预处理中找到每个节点的所有祖先,那么在查询时就能够快速找到两个节点的最低公共祖先。
方法引入
我们可以使用“二进制提升”(BinaryLifting)技术来解决这个问题。这个方法的核心思想是预处理每个节点的所有祖先,以便在查询时快速找到两个节点的最低公共祖先。具体来说,对于每个节点,我们预先计算出它的第?20、21、22、...、2logN?个祖先。有了这些信息后,我们就可以在?logNlogN?的时间复杂度内找到任意两个节点的最低公共祖先。
实现过程
预处理:
使用DFS从根节点开始遍历整棵树,为每个节点计算其所有祖先。
使用数组parent[node][i]?来存储节点?node?的第?2^i个祖先。这样,parent[node][0]?就是节点?node?的直接父节点,parent[node][1]?是节点?node?的第?2?个祖先,依此类推。
当我们已经计算出了?parent[node][i]?和?parent[node][i?1]?时,我们可以使用关系?parent[node][i]=parent[parent[node][i?1]][i?1]?来计算?parent[node][i+1]。
查询:
为了找到两个节点?u和?v的最低公共祖先,首先确保?u?的深度不小于?v。
使用预处理的信息将?u?提升到与?v相同的深度。
如果提升后的?u?和?v相同,则两者就是它们的最低公共祖先。
否则,从最大的?ii?开始,尝试将?u和?v同时向上提升,直到它们有相同的第?2^i个祖先为止。
重复上述过程,直到找到?u和?v的最低公共祖先。
方法优劣分析
优点:
使用“二进制提升”技术,查询的时间复杂度为?logN。
预处理的时间复杂度为?NlogN,空间复杂度也为?NlogN。
缺点:
需要进行预处理,空间复杂度相对较高。
时间复杂度分析
预处理的时间复杂度为?O(NlogN)。
对于每个查询,时间复杂度为O(logN)。
总时间复杂度为O(NlogN+QlogN)=O((N+Q)logN)。
ACCode
C++
#includeiostream
#includevector
#includecmath
#includealgorithm
usingnamespacestd;
constintMAXN=1e5+5;
constintMAXLOG=20;//2^201e5
vectorinttree[MAXN];
intdepth[MAXN];
intparent[MAXN][MAXLOG];
voiddfs(intnode,intprev){
for(inti=1;iMAXLOG;i++){
parent[node][i]=parent[parent[node][i-1]][i-1];
}
for(intchild:tree[node]){
if(child!=prev){
depth[child]=depth[node]+1;
parent[child][0]=node;
dfs(child,node);
}
}
}
intlca(intu,intv){
if(depth[u]depth[v])swap(u,v);
for(inti=MAXLOG-1;i=0;i--){
if(depth[u]-(1i)=depth[v]){
u=parent[u][i];
}
}
if(u==v)returnu;
for(inti=MAXLOG-1;i=0;i--){
if(parent[u][i]!=parent[v][i]){
u=parent[u][i];
v=parent[v][i];
}
}
returnparent[u][0];
}
intmain(){
intN,Q;
cinN;
for(inti=1;iN;i++){
intu,v;
cinuv
文档评论(0)