标签:one flash query sim acm not mes continue lan
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 327680/327680 K (Java/Others)
Total Submission(s): 1049 Accepted Submission(s):
459
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4297
画图发现,实际上这个有向图是一个森林。
首先-1的情况可以用并查集判掉。。
剩下的每一个分离的有向图都可以看做一颗以一个环为根的树。。
然后分两种情况讨论:
1. 两个节点在根的同一颗子树中,那么直接LCA
2. 其余情况,肯定要两个点都先走到环上,然后判断一下就好了。。。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #define LL long long #define N 500050 using namespace std; inline int Read_(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int n,k,cnt=0,tot=0; int fa[N],hed[N],dep[N],cir[N],rt[N],g[N],num[N],len[N]; int F[N][22]; bool vis[N]; struct edge{ int r,nxt; }e[N]; void insert_(int u,int v){ e[++cnt].r=v;e[cnt].nxt=hed[u];hed[u]=cnt; } int find_(int x){ return fa[x]==x?x:fa[x]=find_(fa[x]); } void dfs(int x){ for(int i=1;i<=20;i++) F[x][i]=F[F[x][i-1]][i-1]; for(int i=hed[x];i;i=e[i].nxt) if(!vis[e[i].r]){ dep[e[i].r]=dep[x]+1; rt[e[i].r]=rt[x]; F[e[i].r][0]=x; vis[e[i].r]=1; dfs(e[i].r); } return; } int lca_(int x,int y){ if(dep[x]<dep[y]) swap(x,y); for(int i=0;(1<<i)<=(dep[x]-dep[y]);i++) if( (1<<i)&(dep[x]-dep[y]) ) x=F[x][i]; if(x==y) return x; for(int i=20;i>=0;i--) if(F[x][i]!=F[y][i]){ x=F[x][i];y=F[y][i]; } return F[x][0]; } int main(){ int u,v,w; while(scanf("%d%d",&n,&k)!=EOF){ cnt=0;tot=0; memset(hed,0,sizeof(hed)); memset(vis,0,sizeof(vis)); memset(F,0,sizeof(F)); memset(num,0,sizeof(num)); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=n;i++){ g[i]=Read_();insert_(g[i],i); u=find_(i);v=find_(g[i]); if(u!=v) fa[u]=v; else cir[++tot]=i; } for(int i=1;i<=tot;i++){ int js=1; u=cir[i];dep[u]=0;rt[u]=u;vis[u]=1;num[u]=js;u=g[u]; while(u!=cir[i]){ js++;dep[u]=0;rt[u]=u;vis[u]=1;num[u]=js;u=g[u]; } len[find_(u)]=js; dfs(u);u=g[u]; while(u!=cir[i]){ dfs(u);u=g[u]; } } for(int i=1;i<=k;i++){ u=Read_();v=Read_(); if(find_(u)!=find_(v)){ printf("-1 -1\n"); continue; } if(rt[u]==rt[v]){ w=lca_(u,v); printf("%d %d\n",dep[u]-dep[w],dep[v]-dep[w]); continue; } int ansu,ansv,ansU,ansV; if(num[rt[u]]<num[rt[v]]){ ansu=dep[u]+num[rt[v]]-num[rt[u]]; ansv=dep[v]; ansU=dep[u]; ansV=dep[v]+len[find_(v)]-num[rt[v]]+num[rt[u]]; if(max(ansu,ansv)<max(ansU,ansV)){ printf("%d %d\n",ansu,ansv);continue; } if(max(ansu,ansv)>max(ansU,ansV)){ printf("%d %d\n",ansU,ansV);continue; } if(min(ansu,ansv)<min(ansU,ansV)){ printf("%d %d\n",ansu,ansv);continue; } if(min(ansu,ansv)>min(ansU,ansV)){ printf("%d %d\n",ansU,ansV);continue; } if(ansv<ansV){ printf("%d %d\n",ansu,ansv);continue; } else{ printf("%d %d\n",ansU,ansV);continue; } } else { ansu=dep[u]; ansv=dep[v]+num[rt[u]]-num[rt[v]]; ansU=dep[u]+len[find_(u)]-num[rt[u]]+num[rt[v]]; ansV=dep[v]; if(max(ansu,ansv)<max(ansU,ansV)){ printf("%d %d\n",ansu,ansv);continue; } if(max(ansu,ansv)>max(ansU,ansV)){ printf("%d %d\n",ansU,ansV);continue; } if(min(ansu,ansv)<min(ansU,ansV)){ printf("%d %d\n",ansu,ansv);continue; } if(min(ansu,ansv)>min(ansU,ansV)){ printf("%d %d\n",ansU,ansV);continue; } if(ansv<ansV){ printf("%d %d\n",ansu,ansv);continue; } else{ printf("%d %d\n",ansU,ansV);continue; } } } } return 0; }
This passage is made by Iscream-2001.
HDU 4297--One and One Story(LCA&并查集)
标签:one flash query sim acm not mes continue lan
原文地址:http://www.cnblogs.com/Yuigahama/p/7855785.html