hdu2874

题意:给你一个森林,求某两个点的距离,如果两点不在同一棵树上,输出Not connected;
解题思路:一开始对这种多次访问的lca离线算法不熟悉,要么超时,要么wa;后来,直接在tarjan递归中每访问一个点就只判断与这个点有关的询问,而不是查遍全部询问,这一点害我超时了几次。然后,这题由于是森林,所以要巧妙地对点在那颗树做一下标记,如果询问的两个点不再同一树上直接有不连接的答案,最后还有没注意到作为根结点读入递归时,没有标记为已读,导致有wa了几遍。细节吖...
2432msG++代码

 

#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
using namespace std;
typedef struct edge{
int w,to;
edge(int a,int b){to=a;w=b;}
}edge;
typedef struct quetry
{
int to,id;
quetry(int a,int b){to=a;id=b;}
}quetry;
int cheack[10005],n,m,q,sum[10005],u,v,bin[10005],ans[1000005],bcnt;
bool vs[10005];
vector<edge>g[10005];
vector<quetry>Q[10005];
int find(int x)
{
while(x!=bin[x])
x=bin[x];
return x;
}
void Union(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y)
bin[y]=x;
return ;
}
void tarjan_lca(int x)
{
int i,wp;
wp=sum[x];
for(i=0;i<g[x].size();i++)
{
int y=g[x][i].to;
int w=g[x][i].w;
if(!vs[y])
{
vs[y]=true;
sum[y]=w+wp;
tarjan_lca(y);
Union(x,y);
}
}
cheack[x]=bcnt;//标记属于那棵树
for(i=0;i<Q[x].size();i++)
{
int y=Q[x][i].to;
int id=Q[x][i].id;
if(cheack[y])
{
if(cheack[x]==cheack[y])
ans[id]=sum[x]+sum[y]-2*sum[find(y)];
else//如果不再同一颗树,则不连接
ans[id]=-1;
}
}
}
int main()
{
int x,y,z,i;
while(scanf("%d %d %d",&n,&m,&q)!=EOF)
{
for(i=0;i<=n;i++)
{
vs[i]=false;
cheack[i]=0;
bin[i]=i;
g[i].clear();
Q[i].clear();
sum[i]=0;
}
for(i=0;i<m;i++)
{
scanf("%d %d %d",&x,&y,&z);
g[x].push_back(edge(y,z));
g[y].push_back(edge(x,z));
}
for(i=0;i<q;i++)
{
scanf("%d %d",&u,&v);
Q[u].push_back(quetry(v,i));
Q[v].push_back(quetry(u,i));
}
bcnt=0;
for(i=1;i<=n;i++)
{
if(!vs[i])
{
bcnt++;//用于区分结点属于那个树
vs[i]=true;//根结点要标记为已读!!!
tarjan_lca(i);
}
}
for(i=0;i<q;i++)
if(ans[i]==-1)
printf("Not connected\n");
else
printf("%d\n",ans[i]);
}
return 0;

 

你可能感兴趣的:(森林,离线,connected)