标签: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