您的位置:首页 > 其它

HDU 4297-One and One Story解题报告

2012-09-21 18:35 483 查看
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4297

这道题所给的图是一个森林,每一个子图都必有一个环(因为总边数为n),可以把环当做这棵树的根节点,那么如果两个点不在一棵树上,一定互相不可达,如果在一棵树上,如果两个点在同一棵子树上,那么一起到的点就是LCA,所以要维护森林的LCA,如果不在同一棵子树上,则要到各自的根节点,然后沿着环方向分别判断哪种情况是最优解。

View Code

#pragma comment(linker, "/STACK:10240000000,10240000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 500005
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int nxt
;
int root
;//点是否在环上,在环上是环上的第几个点
int father
;//在环上的父节点
int num
;//所在环的节点个数
int f
;//并查集判断是否是在一个树上,并且可以确定环
int list[2*N];
int fir[2*N],ti;//rmq解决LCA问题
bool used
;
int deep[2*N];
int n;
int head
,cnt;
struct node
{
int v,next;
};
node edge
;//要加反向边
void add(int u,int v)
{
edge[cnt].v=v,edge[cnt].next=head[u],head[u]=cnt++;
}
int find(int x)
{
int r=x;
while(r!=f[r])
r=f[r];
int t1;
while(x!=f[x])
{
t1=f[x];
f[x]=r;
x=t1;
}
return r;
}
void uni(int x,int y)
{
int t1=find(x);
int t2=find(y);
if(t1==t2)//发现一个点和其所要连接的点在一个集合时,说明产生了环
{
int cnt1=0;
int temp=x;
do
{
root[x]=++cnt1;
x=nxt[x];
}while(!root[x]);
x=temp;
num[x]=cnt1;
x=nxt[x];
while(x!=temp)
{
num[x]=cnt1;
x=nxt[x];
}
}
else
f[t1]=t2;
}
int dp[2*N][22];
void makermq()
{
int i,j;
for(i=1;i<ti;i++)
dp[i][0]=deep[i];
for(j=1;(1<<j)<ti;j++)
{
for(i=1;i+(1<<j)-1<ti;i++)
dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
int rmq(int s,int e)
{
int k=(int)(log((e-s+1)*1.0)/log(2.0));
return min(dp[s][k],dp[e-(1<<k)+1][k]);
}
void init()
{
memset(dp,0x3f,sizeof(dp));
memset(root,0,sizeof(root));
memset(num,0,sizeof(num));
memset(head,-1,sizeof(head));
memset(used,0,sizeof(used));
memset(deep,0,sizeof(deep));
memset(fir,0,sizeof(fir));
memset(father,0,sizeof(father));
memset(list,0,sizeof(list));
cnt=0;
ti=1;
int i;
for(i=1;i<=n;i++)
{
f[i]=i;
}
}
void dfs(int u,int d,int v)
{
used[u]=true;
if(root[u])
{
d=1;
v=u;
}
list[ti]=u;
deep[ti]=d;
fir[u]=ti;
ti++;
father[u]=v;
int i;
for(i=head[u];i>=0;i=edge[i].next)
{
if(!used[edge[i].v])
{
dfs(edge[i].v,d+1,v);
list[ti]=u;
deep[ti]=d;
ti++;
}
}
}
int main()
{
int i,j,m,a,b,temp,t1,t2;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(i=1;i<=n;i++)
{
scanf("%d",&nxt[i]);
add(nxt[i],i);
uni(i,nxt[i]);
}
for(i=1;i<=n;i++)
if(root[i]&&(!used[i]))
dfs(i,1,i);
makermq();
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
if(find(a)!=find(b))
{
printf("-1 -1\n");
continue;
}
if(father[a]==father[b])
{
t1=a,t2=b;
if(fir[a]>fir[b])//这里要特别注意
{
t1=b,t2=a;
}
temp=rmq(fir[t1],fir[t2]);
printf("%d %d\n",deep[fir[a]]-temp,deep[fir[b]]-temp);
}
else
{
temp=num[father[a]];
t1=deep[fir[a]]-1;
t2=deep[fir[b]]-1;
int fa=father[a];
int fb=father[b];
int ans1=t1,ans2=t2;
if(root[fa]<root[fb])
{
ans1+=(root[fb]-root[fa]);
ans2+=(root[fa]+num[fa]-root[fb]);
}
else
{
ans1+=(root[fb]+num[fb]-root[fa]);
ans2+=(root[fa]-root[fb]);
}
if(max(ans1,t2)<max(t1,ans2))
{
printf("%d %d\n",ans1,t2);
}
else if(max(ans1,t2)>max(t1,ans2))
{
printf("%d %d\n",t1,ans2);
}
else
{
if(min(ans1,t2)<min(t1,ans2))
{
printf("%d %d\n",ans1,t2);
}
else if(min(ans1,t2)>min(t1,ans2))
{
printf("%d %d\n",t1,ans2);
}
else
{
if(ans1>=t2)
{
printf("%d %d\n",ans1,t2);
}
else
{
printf("%d %d\n",t1,ans2);
}
}
}
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: