约会 Rendezvous:基环树/倍增lca
作者:互联网
提炼:tarjan判环,dfs建树,倍增lca,预处理环两点间距离
我犯的错误:
1.基环树不只有一棵,可以有很多
2.自环不能将其忽略,(对于我的算法)应该将其特殊考虑在算法内
3.代码一定要简洁有力,不能让自己调都恶心
Code
数组含义:
que[N]队列,in_que[N]tarjan判是否入队,dfn[N],low[N],bel[N]点属于的集合
ver[N]根节点的集合编号,to[N],nxt[N],head[N],f[N][20]倍增lca,d[N]深度,bel_rt[N]点属于的树的根
extra[N],Ex[N]特判自环专用,
vector<int>vec[N]tarjan点集合
#include<cstdio> #include<vector> const int L=1<<20|1; char buffer[L],*S,*T; #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++) using namespace std; const int N=5e5+5; int n,k,num_tarjan,num_bian,num_huan,top, que[N],in_que[N],dfn[N],low[N],bel[N],ver[N],to[N],nxt[N],head[N],f[N][20],d[N],bel_rt[N],extra[N],Ex[N]; vector<int>vec[N]; int read(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x; } void add(int x,int y){if(x==y)extra[++extra[0]]=x; to[++num_bian]=y,nxt[num_bian]=head[x],head[x]=num_bian; } inline int max(int a,int b){return a>b?a:b;} inline int min(int a,int b){return a>b?b:a;} void tarjan(int x){ dfn[x]=low[x]=++num_tarjan; que[++top]=x;in_que[x]=1; for(int i=head[x],y;i;i=nxt[i]) if(!dfn[y=to[i]])tarjan(y),low[x]=min(low[x],low[y]); else if(in_que[y])low[x]=min(low[x],dfn[y]); if(dfn[x]==low[x]){ num_huan++; int y; do{ y=que[top--]; in_que[y]=0; vec[num_huan].push_back(y); bel[y]=num_huan; }while(y!=x); if((int)vec[num_huan].size()>1)Ex[++Ex[0]]=num_huan; } } void dfs(int x,int depth,int root){ bel_rt[x]=root; d[x]=depth; for(int i=head[x],y;i;i=nxt[i]){ if(bel[root]!=bel[y=to[i]]&&!d[y=to[i]]){ f[y][0]=x; for(int j=1;j<=19;++j)f[y][j]=f[f[y][j-1]][j-1]; dfs(y,depth+1,root); } } } int get(int x,int y){ if(d[x]<d[y])swap(x,y); for(int i=19;i>=0;--i)if(d[f[x][i]]>=d[y])x=f[x][i]; if(x==y)return y; for(int i=19;i>=0;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[y][0]; } int main(){ n=read(),k=read(); for(int i=1;i<=n;++i)add(read(),i); for(int i=1;i<=n;++i)if(!dfn[i])tarjan(i); for(int hua=1;hua<=Ex[0];++hua){int huan=Ex[hua]; for(int i=0;i<(int)vec[huan].size();++i){ dfs(vec[huan][i],1,vec[huan][i]); ver[vec[huan][i]]=i+1; } } for(int i=1;i<=extra[0];++i) if(!d[extra[i]]){ dfs(extra[i],1,extra[i]); ver[extra[i]]=1; } for(int i=1,x,y;i<=k;++i){ x=read(),y=read(); if(bel[bel_rt[x]]!=bel[bel_rt[y]]) printf("-1 -1\n"); else if(bel_rt[x]==bel_rt[y]){ int lca=get(x,y); printf("%d %d\n",d[x]-d[lca],d[y]-d[lca]); } else{ int ai=d[x]-1,bi=d[y]-1,huan_dis=(int)vec[bel[bel_rt[x]]].size(); int len_b=ver[bel_rt[x]]-ver[bel_rt[y]],len_a; if(len_b<0)len_a=-1*len_b,len_b=huan_dis-len_a; else len_a=huan_dis-len_b; int Ma=max(ai+len_a,bi),Mb=max(ai,bi+len_b),ma=min(ai+len_a,bi),mb=min(ai,bi+len_b); //条件一 if(Ma<Mb) printf("%d %d\n",ai+len_a,bi); else if(Ma>Mb) printf("%d %d\n",ai,bi+len_b); else{ //条件二 if(ma<mb) printf("%d %d\n",ai+len_a,bi); else if(ma>mb) printf("%d %d\n",ai,bi+len_b); else{ //条件三 if(ai+len_a>=bi) printf("%d %d\n",ai+len_a,bi); else printf("-1 -1\n"); } } } } return 0; }
标签:tarjan,bel,int,lca,基环树,num,que,low,Rendezvous 来源: https://www.cnblogs.com/hzoi2018-xuefeng/p/11175296.html