洛谷3379(LCA模板优化)
来源:互联网 发布:有个卖时间的软件 编辑:程序博客网 时间:2024/06/06 20:59
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<bits/stdc++.h>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=v; //edges[cnt].to=head[u]; //head[u]=cnt++; edges[cnt].from=u; edges[cnt++].to=v; //cout<<"添加"<<edges[cnt-1].from<<" "<<edges[cnt-1].to<<endl; EdgeNode *e; e=(EdgeNode *)malloc(sizeof(EdgeNode)); e->adjvex=cnt-1; if(G[u].flag==0) G[u].firstarc=NULL,G[u].flag++; e->next=G[u].firstarc; G[u].firstarc=e; //cout<<"目前与节点"<<u<<"连接的一个节点在边集数组的位置" //<<G[u].firstarc->adjvex<<endl;}void init(){ cnt=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=1;i<=s;++i){ grand[x][i]=grand[grand[x][i-1]][i-1]; //gdis[x][i]=gdis[x][i-1]+gdis[grand[x][i-1]][i-1]; //gmax[x][i]=max(gmax[x][i-1],gmax[grand[x][i-1]][i-1]); //if(!grand[x][i]) break; } for(int i=0;G[x].firstarc!=NULL;++i){ //cout<<edges[G[x].firstarc->adjvex].to<<"TEST"<<endl; int tt=edges[G[x].firstarc->adjvex].to; G[x].firstarc=G[x].firstarc->next; if(tt!=grand[x][0]){ depth[tt]=depth[x]+1; grand[tt][0]=x; //gdis[e.to][0]=e.dist; //gmax[e.to][0]=e.dist; dfs(tt); } }}int lca(int a,int b)//最大值,路径权值和{ if(depth[a]>depth[b]) swap(a,b); //ans=0;//路径权值和 //maxx=gmax[b][0]; //for(int i=s;i>=0;i--) // if(depth[a]<depth[b]&&depth[grand[b][i]]>=depth[a]) // b=grand[b][i]; int dre=depth[b]-depth[a]; for(int i=s;i>=0;--i){ if(dre&(1<<i)) b=grand[b][i]; } if(a==b) return a; for(int i=s;i>=0;i--) if(grand[a][i]!=grand[b][i]){ //ans+=gdis[a][i],ans+=gdis[b][i]; //maxx=max(maxx,gmax[a][i]),maxx=max(maxx,gmax[b][i]); a=grand[a][i],b=grand[b][i]; } //ans+=gdis[a][0]; //ans+=gdis[b][0]; //maxx=max(maxx,gmax[a][0]); //maxx=max(maxx,gmax[b][0]); return grand[a][0];}int read(){ char ch='*'; while(!isdigit(ch=getchar()));//不是数字读掉 int num=ch-'0'; while(isdigit(ch=getchar())) num=num*10+ch-'0'; return num;}int main(){ init(); int query,u,v,w; scanf("%d %d %d",&n,&query,&root); s=floor(log(n+0.0)/log(2.0))+1; for(int i=1;i<=n-1;++i){ u=read(); v=read(); addEdge(u,v); addEdge(v,u); } dfs(root);//以root为根结点建树 for(int i=1;i<=query;++i){ u=read(); v=read(); printf("%d\n",lca(u,v)); } return 0;}
代码示例(链式向前星)
#include<bits/stdc++.h>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 head[2*maxn];int depth[maxn];int n;//结点数int s;//倍增最大步数int root;//根节点int cnt;//边集数void addEdge(int u,int v){ edges[cnt].from=v; edges[cnt].to=head[u]; head[u]=cnt++;}void init(){ cnt=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=1;i<=s;++i){ grand[x][i]=grand[grand[x][i-1]][i-1]; //gdis[x][i]=gdis[x][i-1]+gdis[grand[x][i-1]][i-1]; //gmax[x][i]=max(gmax[x][i-1],gmax[grand[x][i-1]][i-1]); //if(!grand[x][i]) break; } for(int i=head[x];i!=-1;i=edges[i].to){ int tt=edges[i].from; if(tt!=grand[x][0]){ depth[tt]=depth[x]+1; grand[tt][0]=x; //gdis[e.to][0]=e.dist; //gmax[e.to][0]=e.dist; dfs(tt); } }}int lca(int a,int b)//最大值,路径权值和{ if(depth[a]>depth[b]) swap(a,b); //ans=0;//路径权值和 //maxx=gmax[a][0]; //for(int i=s;i>=0;i--) // if(depth[a]<depth[b]&&depth[grand[b][i]]>=depth[a]) // b=grand[b][i]; int dre=depth[b]-depth[a]; for(int i=s;i>=0;--i){ if(dre&(1<<i)) b=grand[b][i]; } if(a==b) return a; for(int i=s;i>=0;i--) if(grand[a][i]!=grand[b][i]){ //ans+=gdis[a][i],ans+=gdis[b][i]; //maxx=max(maxx,gmax[a][i]),maxx=max(maxx,gmax[b][i]); a=grand[a][i],b=grand[b][i]; } //ans+=gdis[a][0]; //ans+=gdis[b][0]; //maxx=max(maxx,gmax[a][0]); //maxx=max(maxx,gmax[b][0]); return grand[a][0];}int read(){ char ch='*'; while(!isdigit(ch=getchar()));//不是数字读掉 int num=ch-'0'; while(isdigit(ch=getchar())) num=num*10+ch-'0'; return num;}int main(){ init(); int query,u,v,w; scanf("%d %d %d",&n,&query,&root); s=floor(log(n+0.0)/log(2.0))+1; for(int i=1;i<=n-1;++i){ u=read(); v=read(); addEdge(u,v); addEdge(v,u); } dfs(root);//以root为根结点建树 for(int i=1;i<=query;++i){ u=read(); v=read(); printf("%d\n",lca(u,v)); } return 0;}
阅读全文
1 0
- 洛谷3379(LCA模板优化)
- 洛谷 P 3379 【模板】最近公共祖先(LCA)
- 【洛谷】3379 【模板】最近公共祖先(LCA)
- 洛谷 3379_【模板】最近公共祖先(LCA)
- Luogu-3379 (LCA模板)
- LCA模板(倍增)
- LCA(模板)
- LCA----【模板】最近公共祖先(LCA)
- 【模板】LCA Tarjan算法 (模板题:洛谷P3379)
- LCA之树链剖分(模板)
- [luogu-3379]【模板】最近公共祖先(LCA) 题解
- 洛谷 P3379 【模板】最近公共祖先(LCA)
- 洛谷P3379 【模板】最近公共祖先(LCA)
- 洛谷 P3379 【模板】最近公共祖先(LCA)
- 洛谷 P3379 【模板】最近公共祖先(LCA)
- LCA模板
- LCA模板
- LCA模板
- spring IOC和DI
- 31. Next Permutation
- HDOJ1176 免费馅饼 简单的二维DP
- celery+Rabbit MQ的安装和使用
- 20170811
- 洛谷3379(LCA模板优化)
- 单行注释、多行注释、文档注释最完美的解释、导出API
- Java_23种设计模式(一)
- 笔记本无缘无故自动唤醒是怎么回事?
- 虚拟机CentOS7安装python3.6.2及requests模块的问题汇总
- Android中MediaCodec的使用
- 51nod-1434 区间LCM
- docker在windows 7上连接终端(ssh)
- How to switch xcode on Mac?