BZOJ 2791 Poi2012 Rendezvous 倍增LCA
来源:互联网 发布:centos 7 jdk rpm 编辑:程序博客网 时间:2024/06/01 07:15
题目大意:给定一棵内向森林,多次给定两个点a和b,求点对(x,y)满足:
1.从a出发走x步和从b出发走y步会到达同一个点
2.在1的基础上如果有多解,那么要求max(x,y)最小
3.在1和2的基础上如果有多解,那么要求min(x,y)最小
4.如果在1、2、3的基础上仍有多解,那么要求x>=y
因此那个x>=y是用来省掉SPJ的,不是题目要求- -
容易发现:
如果a和b不在同一棵内向树上,显然无解,否则一定有解
定义根为从一个点出发能走到的第一个环上点,如果a和b的根相同,则到达LCA是最优的
否则到达的点一定是a的根和b的根中的一个,两种情况都计算一下,取最优解即可
《倍增LCA万年写不对系列》
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 500500using namespace std;int n,q,T;int a[M],v[M],on_ring[M],pos[M],size[M];int fa[M][20],dpt[M],root[M];void DFS(int x){v[x]=T;if(v[a[x]]==T){int i,temp=1;for(i=x;temp==1||i!=x;i=a[i],temp++)on_ring[i]=T,pos[i]=temp,root[i]=i;size[T]=temp-1;return ;}if(!v[a[x]])DFS(a[x]);if(!on_ring[x]){fa[x][0]=a[x];dpt[x]=dpt[a[x]]+1;root[x]=root[a[x]];}}int LCA(int x,int y){int j;if(dpt[x]<dpt[y])swap(x,y);for(j=19;~j;j--)if(dpt[fa[x][j]]>=dpt[y])x=fa[x][j];if(x==y) return x;for(j=19;~j;j--)if(fa[x][j]!=fa[y][j])x=fa[x][j],y=fa[y][j];return fa[x][0];}int Distance(int x,int y,int p){return (y-x+p)%p;}void Solve(int x,int y){if(on_ring[root[x]]!=on_ring[root[y]]){printf("%d %d\n",-1,-1);return ;}if(root[x]==root[y]){int lca=LCA(x,y);printf("%d %d\n",dpt[x]-dpt[lca],dpt[y]-dpt[lca]);return ;}int fx=root[x],fy=root[y];int x1=dpt[x]+Distance(pos[fx],pos[fy],size[on_ring[fx]]),y1=dpt[y];int x2=dpt[x],y2=dpt[y]+Distance(pos[fy],pos[fx],size[on_ring[fy]]);if(max(x1,y1)!=max(x2,y2)){if(max(x1,y1)<max(x2,y2))printf("%d %d\n",x1,y1);elseprintf("%d %d\n",x2,y2);return ;}if(min(x1,y1)!=min(x2,y2)){if(min(x1,y1)<min(x2,y2))printf("%d %d\n",x1,y1);elseprintf("%d %d\n",x2,y2);return ;}printf("%d %d\n",max(x1,y1),min(x1,y1));}int main(){int i,j,x,y;cin>>n>>q;for(i=1;i<=n;i++)scanf("%d",&a[i]);for(i=1;i<=n;i++)if(!v[i])++T,DFS(i);for(j=1;j<=19;j++)for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];for(i=1;i<=q;i++){scanf("%d%d",&x,&y);Solve(x,y);}return 0;}
0 0
- BZOJ 2791 Poi2012 Rendezvous 倍增LCA
- bzoj 2791 [Poi2012]Rendezvous 倍增lca 基环树
- [BZOJ 2791]POI2012 Rendezvous
- [POI 2012]Rendezvous(倍增LCA)
- BZOJ2791: [Poi2012]Rendezvous
- BZOJ2791/POI2012 Rendezvous
- BZOJ2791: [Poi2012]Rendezvous
- BZOJ 3732 Network Kruskal+倍增LCA
- BZOJ 1787 AHOI2008 紧急集合 倍增LCA
- 【BZOJ 1832】 [AHOI2008]聚会|倍增lca
- BZOJ 4144 Dijkstra+Kruskal+倍增LCA
- 倍增LCA(bzoj 3732: Network)
- BZOJ 3712 Fiolki (倍增LCA)
- bzoj 2144: 跳跳棋 lca+倍增
- lca倍增
- lca(倍增)
- 倍增LCA
- 倍增lca
- 线程间通信
- Code[VS] 3377 接水问题2
- 用Gradle 构建您的android程序
- JAVA实现精确的加减乘除
- 安卓程序退出的讨论
- BZOJ 2791 Poi2012 Rendezvous 倍增LCA
- [LeetCode] 015. 3Sum (Medium) (C++/Java/Python)
- UITableView的静态表格的注意事项
- Admob(6.12.x)符号未定义错误的解决方法(IOS)
- Smallest Difference (poj 2718 暴力枚举)
- C#打印九九乘法表
- 12、Integer to Roman
- 备忘:linux去bom头
- ZipAlign对apk进行优化