热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

洛谷3379(LCA模板优化)

problem题目描述如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。输入格式:第一行包含三个正整数N、M、S&#x

problem

题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式:

输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

输入样例#1:

5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5

输出样例#1:

4
4
1
4
4

思路

数据量可以到500000点 500000询问 提交果然卡常了

1.读入可以用getchar优化(次要)

2.vector较链表在数据量大的时候是慢的(希望有大神可以系统的说明下这个vector的复杂度分析),可以用链式邻接表或者链式前向星模拟邻接表


代码示例(链式邻接表)

#include
using namespace std;
const int maxn=500010;//节点数struct Edge{int from,to;
}edges[2*maxn];const int maxlog=30;
int grand[maxn][maxlog];
//int gdis[maxn][maxlog];
//int gmax[maxn][maxlog];
int depth[maxn];
int n;//结点数
int s;//倍增最大步数
int root;//根节点
int cnt;//边集数struct EdgeNode{int adjvex;//顶点编号EdgeNode *next;
};struct AdList{int flag;EdgeNode *firstarc;
}G[maxn];void addEdge(int u,int v){//edges[cnt].from&#61;v;//edges[cnt].to&#61;head[u];//head[u]&#61;cnt&#43;&#43;;edges[cnt].from&#61;u;edges[cnt&#43;&#43;].to&#61;v;//cout<<"添加"<EdgeNode *e;e&#61;(EdgeNode *)malloc(sizeof(EdgeNode));e->adjvex&#61;cnt-1;if(G[u].flag&#61;&#61;0) G[u].firstarc&#61;NULL,G[u].flag&#43;&#43;;e->next&#61;G[u].firstarc;G[u].firstarc&#61;e;//cout<<"目前与节点"<//<adjvex<
}void init()
{cnt&#61;0;memset(grand,0,sizeof(grand));//memset(head,-1,sizeof(head));memset(depth,0,sizeof(depth));//memset(gdis,0,sizeof(gdis));//memset(gmax,0,sizeof(gmax));
}void dfs(int x)//预处理
{for(int i&#61;1;i<&#61;s;&#43;&#43;i){grand[x][i]&#61;grand[grand[x][i-1]][i-1];//gdis[x][i]&#61;gdis[x][i-1]&#43;gdis[grand[x][i-1]][i-1];//gmax[x][i]&#61;max(gmax[x][i-1],gmax[grand[x][i-1]][i-1]);//if(!grand[x][i]) break;}for(int i&#61;0;G[x].firstarc!&#61;NULL;&#43;&#43;i){//cout<adjvex].to<<"TEST"<int tt&#61;edges[G[x].firstarc->adjvex].to;G[x].firstarc&#61;G[x].firstarc->next;if(tt!&#61;grand[x][0]){depth[tt]&#61;depth[x]&#43;1;grand[tt][0]&#61;x;//gdis[e.to][0]&#61;e.dist;//gmax[e.to][0]&#61;e.dist;dfs(tt);}}
}int lca(int a,int b)//最大值&#xff0c;路径权值和
{if(depth[a]>depth[b]) swap(a,b);//ans&#61;0;//路径权值和//maxx&#61;gmax[b][0];//for(int i&#61;s;i>&#61;0;i--)// if(depth[a]&#61;depth[a])// b&#61;grand[b][i];int dre&#61;depth[b]-depth[a];for(int i&#61;s;i>&#61;0;--i){if(dre&(1<if
(a&#61;&#61;b) return a;for(int i&#61;s;i>&#61;0;i--)if(grand[a][i]!&#61;grand[b][i]){//ans&#43;&#61;gdis[a][i],ans&#43;&#61;gdis[b][i];//maxx&#61;max(maxx,gmax[a][i]),maxx&#61;max(maxx,gmax[b][i]);a&#61;grand[a][i],b&#61;grand[b][i];}//ans&#43;&#61;gdis[a][0];//ans&#43;&#61;gdis[b][0];//maxx&#61;max(maxx,gmax[a][0]);//maxx&#61;max(maxx,gmax[b][0]);return grand[a][0];
}int read()
{char ch&#61;&#39;*&#39;;while(!isdigit(ch&#61;getchar()));//不是数字读掉int num&#61;ch-&#39;0&#39;;while(isdigit(ch&#61;getchar())) num&#61;num*10&#43;ch-&#39;0&#39;;return num;
}int main()
{init();int query,u,v,w;scanf("%d %d %d",&n,&query,&root);s&#61;floor(log(n&#43;0.0)/log(2.0))&#43;1;for(int i&#61;1;i<&#61;n-1;&#43;&#43;i){u&#61;read();v&#61;read();addEdge(u,v);addEdge(v,u);}dfs(root);//以root为根结点建树for(int i&#61;1;i<&#61;query;&#43;&#43;i){u&#61;read();v&#61;read();printf("%d\n",lca(u,v));}return 0;
}


代码示例(链式向前星)

#include
using namespace std;
const int maxn&#61;500010;//节点数struct Edge{int from,to;
}edges[2*maxn];const int maxlog&#61;30;
int grand[maxn][maxlog];
//int gdis[maxn][maxlog];
//int gmax[maxn][maxlog];
int head[2*maxn];
int depth[maxn];
int n;//结点数
int s;//倍增最大步数
int root;//根节点
int cnt;//边集数void addEdge(int u,int v){edges[cnt].from&#61;v;edges[cnt].to&#61;head[u];head[u]&#61;cnt&#43;&#43;;
}void init()
{cnt&#61;0;memset(grand,0,sizeof(grand));memset(head,-1,sizeof(head));memset(depth,0,sizeof(depth));//memset(gdis,0,sizeof(gdis));//memset(gmax,0,sizeof(gmax));
}void dfs(int x)//预处理
{for(int i&#61;1;i<&#61;s;&#43;&#43;i){grand[x][i]&#61;grand[grand[x][i-1]][i-1];//gdis[x][i]&#61;gdis[x][i-1]&#43;gdis[grand[x][i-1]][i-1];//gmax[x][i]&#61;max(gmax[x][i-1],gmax[grand[x][i-1]][i-1]);//if(!grand[x][i]) break;}for(int i&#61;head[x];i!&#61;-1;i&#61;edges[i].to){int tt&#61;edges[i].from;if(tt!&#61;grand[x][0]){depth[tt]&#61;depth[x]&#43;1;grand[tt][0]&#61;x;//gdis[e.to][0]&#61;e.dist;//gmax[e.to][0]&#61;e.dist;dfs(tt);}}
}int lca(int a,int b)//最大值&#xff0c;路径权值和
{if(depth[a]>depth[b]) swap(a,b);//ans&#61;0;//路径权值和//maxx&#61;gmax[a][0];//for(int i&#61;s;i>&#61;0;i--)// if(depth[a]&#61;depth[a])// b&#61;grand[b][i];int dre&#61;depth[b]-depth[a];for(int i&#61;s;i>&#61;0;--i){if(dre&(1<if(a&#61;&#61;b) return a;for(int i&#61;s;i>&#61;0;i--)if(grand[a][i]!&#61;grand[b][i]){//ans&#43;&#61;gdis[a][i],ans&#43;&#61;gdis[b][i];//maxx&#61;max(maxx,gmax[a][i]),maxx&#61;max(maxx,gmax[b][i]);a&#61;grand[a][i],b&#61;grand[b][i];}//ans&#43;&#61;gdis[a][0];//ans&#43;&#61;gdis[b][0];//maxx&#61;max(maxx,gmax[a][0]);//maxx&#61;max(maxx,gmax[b][0]);return grand[a][0];
}int read()
{char ch&#61;&#39;*&#39;;while(!isdigit(ch&#61;getchar()));//不是数字读掉int num&#61;ch-&#39;0&#39;;while(isdigit(ch&#61;getchar())) num&#61;num*10&#43;ch-&#39;0&#39;;return num;
}int main()
{init();int query,u,v,w;scanf("%d %d %d",&n,&query,&root);s&#61;floor(log(n&#43;0.0)/log(2.0))&#43;1;for(int i&#61;1;i<&#61;n-1;&#43;&#43;i){u&#61;read();v&#61;read();addEdge(u,v);addEdge(v,u);}dfs(root);//以root为根结点建树for(int i&#61;1;i<&#61;query;&#43;&#43;i){u&#61;read();v&#61;read();printf("%d\n",lca(u,v));}return 0;
}


推荐阅读
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
author-avatar
jfgkj6454_478
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有