HDU 5266 HDU 2586 LCA问题
来源:互联网 发布:淘宝好评返现处罚规则 编辑:程序博客网 时间:2024/06/11 22:01
首先来一发基于RMQ-ST的LCA模板
#pragma comment(linker, "/STACK:1024000000,1024000000")#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<iostream>#include<algorithm>#include<sstream>#include<fstream>#include<vector>#include<map>#include<stack>#include<list>#include<set>#include<queue>#define LL long long#define lson l,m,rt<<1#define rson m+1,r,rt<<1 | 1using namespace std;const int maxn=100005,inf=1<<29;int dir[][2]={ {0,1},{-1,0},{0,-1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}};int n,m,t,root;/*给定一棵树,求某两个树节点的最近公共祖先。算法复杂度O(n+(2*n-1)*log(2*n-1)+m)o(n)为DFS遍历复杂度,o((2*n-1)*log(2*n-1))为RMQ-ST初始化复杂度有m个查询,对于每个查询都是o(1),故查询总复杂度为o(m)n一般较大,则递归深度达,必然会爆栈故需要用黑科技#pragma comment(linker, "/STACK:1024000000,1024000000")调整虚拟栈的大小,但是这条代码只能在C++编译器中编译,故需要用C++提交而C++对STL支持比较差,故用vector建图会导致TLE,所以用静态链表建图*/struct node{ int to,next,w;}edge[maxn];//存放邻接表的边int head[maxn],cnt;//邻接表表头和总边数void add(int from,int to,int w)//往邻接表加边{ edge[cnt].to=to; edge[cnt].w=w; edge[cnt].next=head[from]; head[from]=cnt++;}int vs[maxn<<1];//DFS访问的顺序int depth[maxn<<1];//节点的深度int id[maxn];//各个顶点在vs中首次出现的下标int dp[maxn<<1][20];//维护RMQ-STvoid init_rmq_index(int a[],int n)//基于寻找下标的RMQ-ST初始化{ for(int i=0;i<n;i++) dp[i][0]=i; for(int j=1;(1<<j)<=n;j++) for(int i=0;i+(1<<j)-1<n;i++) if(a[dp[i][j-1]]<a[dp[i+(1<<(j-1))][j-1]]) dp[i][j]=dp[i][j-1]; else dp[i][j]=dp[i+(1<<(j-1))][j-1];}int rmq_index(int a[],int l,int r)//RMQ-ST查询{ int k=(int)(log(1.0*(r-l+1))/log(2.0)); if(a[dp[l][k]]<a[dp[r-(1<<k)+1][k]]) return dp[l][k]; else return dp[r-(1<<k)+1][k];}void dfs(int v,int p,int d,int &k)//获取顶点DFS序,以及深度,首次出现位置{ id[v]=k; vs[k]=v; depth[k++]=d; for(int i=head[v];i!=-1;i=edge[i].next) { int to=edge[i].to; if(to!=p) { dfs(to,v,d+1,k); vs[k]=v; depth[k++]=d; } }}void init(int V)//初始化LCA{ int k=0; dfs(root,-1,0,k); init_rmq_index(depth,V*2-1);}int LCA(int u,int v)//LCA查询{ int l=min(id[u],id[v]),r=max(id[u],id[v]); int pos=rmq_index(depth,l,r); return vs[pos];}int main(){ //freopen("HDU2586_in.txt","r",stdin); scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); cnt=0; memset(head,-1,sizeof(head)); for(int i=0;i<n-1;i++) { int x,y,w; scanf("%d%d%d",&x,&y,&w); add(x,y,w); add(y,x,w); } root=1; init(n); int l,r; for(int i=0;i<m;i++) { scanf("%d%d",&l,&r); printf("%d\n",LCA(l,r)); } } return 0;}
题目链接:2586
题目大意,给出一棵根为1的树,然后给出一些询问,每个询问包含两个节点,求两个节点的最短距离。
当然这题数据比较小可以用DFS水过~
不过用LCA来解决就比较高效了。首先预处理出每个节点分别都根节点的距离。
然后对于某两个节点a,b,可以求出最近公共祖先,所以有d=dis[a]+dis[b]-2*dis[LCA(a,b)];
算是对模板的一个应用吧。
另:网上都是一些抄袭狗啊,我就没见到用基于RMQ-ST来解决LCA的,都是用跳表或者是离线搞的。
下面是AC代码
#pragma comment(linker, "/STACK:1024000000,1024000000")#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<iostream>#include<algorithm>#include<sstream>#include<fstream>#include<vector>#include<map>#include<stack>#include<list>#include<set>#include<queue>#define LL long long#define lson l,m,rt<<1#define rson m+1,r,rt<<1 | 1using namespace std;const int maxn=100005,inf=1<<29;int dir[][2]={ {0,1},{-1,0},{0,-1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}};int n,m,t,root;struct node{ int to,next,w;}edge[maxn];int head[maxn],cnt;void add(int from,int to,int w){ edge[cnt].to=to; edge[cnt].w=w; edge[cnt].next=head[from]; head[from]=cnt++;}int vs[maxn<<1];//DFS访问的顺序int depth[maxn<<1];//节点的深度int id[maxn];//各个顶点在vs中首次出现的下标int dp[maxn<<1][20],dis[maxn];void init_rmq_index(int a[],int n){ for(int i=0;i<n;i++) dp[i][0]=i; for(int j=1;(1<<j)<=n;j++) for(int i=0;i+(1<<j)-1<n;i++) if(a[dp[i][j-1]]<a[dp[i+(1<<(j-1))][j-1]]) dp[i][j]=dp[i][j-1]; else dp[i][j]=dp[i+(1<<(j-1))][j-1];}int rmq_index(int a[],int l,int r){ int k=(int)(log(1.0*(r-l+1))/log(2.0)); if(a[dp[l][k]]<a[dp[r-(1<<k)+1][k]]) return dp[l][k]; else return dp[r-(1<<k)+1][k];}void dfs(int v,int p,int d,int &k){ id[v]=k; vs[k]=v; depth[k++]=d; for(int i=head[v];i!=-1;i=edge[i].next) { int to=edge[i].to; if(to!=p) { dis[to]=dis[v]+edge[i].w; dfs(to,v,d+1,k); vs[k]=v; depth[k++]=d; } }}void init(int V){ int k=0; for(int i=0;i<=V;i++) dis[i]=-1; //memset(dis,-1,sizeof(dis)); dis[root]=0; dfs(root,-1,0,k); init_rmq_index(depth,V*2-1);}int LCA(int u,int v){ int l=min(id[u],id[v]),r=max(id[u],id[v]); int pos=rmq_index(depth,l,r); return vs[pos];}int main(){ //freopen("HDU2586_in.txt","r",stdin); scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); cnt=0; memset(head,-1,sizeof(head)); for(int i=0;i<n-1;i++) { int x,y,w; scanf("%d%d%d",&x,&y,&w); add(x,y,w); add(y,x,w); // G[x].push_back(node(y,w)); //G[y].push_back(node(x,w)); // printf("yes\n"); } root=1; init(n);/* for(int i=0;i<2*n-1;i++) printf("%d ",vs[i]); printf("\n"); for(int i=0;i<2*n-1;i++) printf("%d ",depth[i]); printf("\n"); for(int i=1;i<=n;i++) printf("%d ",id[i]); printf("\n"); for(int i=1;i<=n;i++) printf("%d ",dis[i]); printf("\n");*/ int l,r; for(int i=0;i<m;i++) { scanf("%d%d",&l,&r); //printf("LCA(%d,%d) = %d\n",l,r,LCA(l,r)); printf("%d\n",dis[l]+dis[r]-2*dis[LCA(l,r)]); } } return 0;}2:考虑dfs序,通过在简单的证明可知L~R的LCA为L~R中dfs序较小的那个位置与dfs序较大的那个位置的LCA。因此只要通过st表处理L~R最大dfs序与最小dfs序的编号即可。
求L~R中dfs序较小的那个位置与dfs序较大的那个位置,如果还是用ST表维护,那非常耗内存,故可以牺牲时间换空间,用线段树来维护RMQ。这样内存的使用就比较充足了。
下面是AC代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<iostream>#include<algorithm>#include<sstream>#include<fstream>#include<vector>#include<map>#include<stack>#include<list>#include<set>#include<queue>#define LL long long#define lson l,m,rt<<1#define rson m+1,r,rt<<1 | 1using namespace std;const int maxn=300005,inf=1<<29;int n,m,t,root,minl,maxr;struct node{ int to,next;//,w;}edge[maxn<<1];int head[maxn],cnt;void add(int from,int to){ edge[cnt].to=to; //edge[cnt].w=w; edge[cnt].next=head[from]; head[from]=cnt++;}int vs[maxn<<1];//DFS访问的顺序int depth[maxn<<1];//节点的深度int id[maxn];//各个顶点在vs中首次出现的下标int dp[maxn<<1][20],Min[maxn<<2],Max[maxn<<2];void init_rmq_index(int a[],int n){ for(int i=0;i<n;i++) dp[i][0]=i; for(int j=1;(1<<j)<=n;j++) for(int i=0;i+(1<<j)-1<n;i++) if(a[dp[i][j-1]]<a[dp[i+(1<<(j-1))][j-1]]) dp[i][j]=dp[i][j-1]; else dp[i][j]=dp[i+(1<<(j-1))][j-1];}int rmq_index(int a[],int l,int r){ int k=(int)(log(1.0*(r-l+1))/log(2.0)); if(a[dp[l][k]]<a[dp[r-(1<<k)+1][k]]) return dp[l][k]; else return dp[r-(1<<k)+1][k];}void PushUp(int rt){ Min[rt]=min(Min[rt<<1],Min[rt<<1|1]); Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);}void build(int l,int r,int rt){ if(l==r) { Min[rt]=Max[rt]=id[l]; return ; } int m=(l+r)>>1; build(lson); build(rson); PushUp(rt);}void Query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R) { minl=min(minl,Min[rt]); maxr=max(maxr,Max[rt]); return ; } int m=(l+r)>>1,ans=1<<30; if(L<=m) Query(L,R,lson); if(R>m) Query(L,R,rson); //return ans;}void dfs(int v,int p,int d,int &k){ id[v]=k; vs[k]=v; depth[k++]=d; for(int i=head[v];i!=-1;i=edge[i].next) if(edge[i].to!=p) { dfs(edge[i].to,v,d+1,k); vs[k]=v; depth[k++]=d; }}void init(int V){ int k=0; dfs(root,-1,0,k); init_rmq_index(depth,V*2-1); build(1,V,1);}int LCA(int u,int v){ // int l,r; //rmq(u,v,l,r); int pos=rmq_index(depth,u,v); return vs[pos];}int main(){ // freopen("HDU5226_in.txt","r",stdin); // scanf("%d",&t); while(~scanf("%d",&n)) { cnt=0; memset(head,-1,sizeof(head)); for(int i=0;i<n-1;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); //G[x].push_back(y); //G[y].push_back(x); } root=1; init(n); int l,r; scanf("%d",&m); while(m--) { scanf("%d%d",&l,&r); minl=1<<30,maxr=-1; Query(l,r,1,n,1); printf("%d\n",LCA(minl,maxr)); } } return 0;}
0 0
- HDU 5266 HDU 2586 LCA问题
- HDU 2586 LCA
- HDU - 2586 LCA
- HDU 2586 LCA
- 【HDU 2586】LCA模板
- hdu 2586 LCA
- hdu 2586 lca入门
- lca模板 hdu 2586
- HDU 2586 LCA
- HDU 2586 How far away ? LCA处理边权问题
- hdu 5266(线段树+LCA)
- 周赛 HDU 2874 HDU 2586 LCA
- HDU 2586 lca 最近祖先
- hdu 2586 lca模板题
- hdu 2586 lca离线tarjan
- HDU 2586 【LCA-Tarjan-模板】
- hdu 2586在线LCA RMQ
- HDU 2586 LCA转RMQ
- MyEclipse+Struts+Spring+Hibernate 环境配置
- Android中的选择器selector的写法解析及不起作用原因
- 数据库复习1——数据库体系结构和关系系统
- Announce of Looksery Cup 2015-B. Looksery Party
- Integer.toHexString(int)得到byte类型的十六进制字符串形式
- HDU 5266 HDU 2586 LCA问题
- silicon_status用这个标志来控制灯的状态
- 金蝶条码标签打印无缝对接金蝶K3接口金蝶KIS条码标签打印金蝶单据打印条码标签打印
- Qt学习笔记--编程技巧总结
- SQL结构化查询语言及Mysql基本操作
- 美国政府网站将强制实现全站HTTPS加密,值得我国政府借鉴
- MVP模式与MVC模式
- HTML代码导出EXCEL数字前面的0消失解决办法
- Leetcode[35]-Search Insert Position