HDU2874 Connections between cities 最近公共祖先

      

      第一次按常规的方法求,将所有的查询的u,v,和最近公共祖先都保存起来,然后用tarjan+并查集求最近公共祖先。因为询问的次数过多,所以在保存查询的时候总是MLE,后来参考了一下别人的代码,才突然觉悟,可以先将u,v,和其最近公共祖先保存到数组,然后再求结果,为什么不能直接保存其结果了。如果只保存结果的话,保存查询操作就可以节约1/3的内存,所以基本可以过了。

代码如下:

   方法一:

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const  int maxn = 10100;
vector<pair<int,int> >tree[maxn],query[maxn];
int father[2][maxn],res[1000010],dis[maxn],vis[maxn];

void init(int n)
{
    memset(vis,0,sizeof(vis));
    memset(dis,0,sizeof(dis));
    memset(res,-1,sizeof(res));
    for( int i = 0; i <= n; i++){
        tree[i].clear();
        query[i].clear();
        father[0][i] = father[1][i] = i;
    }
}
int find(int x,int k){
    if( x != father[k][x])
    return father[k][x] = find(father[k][x],k);
    return father[k][x];
}
void LCA(int u){
    vis[u] = 1;

    pair<int,int>x;
    int i,size = query[u].size();
    for(  i = 0; i < size; i++){
        x = query[u][i];
        if( vis[x.first])
           res[x.second] = dis[u] + dis[x.first] - 2*dis[find(x.first,0)];
    }

    size = tree[u].size();
    for( i = 0; i < size; i++){
        x = tree[u][i];
        if( !vis[x.first] ){
            dis[x.first] = dis[u] + x.second;
            LCA(x.first);
            union_set(x.first,u,0);
        }
    }
}
void union_set(int x,int y,int k){
    x = find(x,k);
    y = find(y,k);
    if ( x != y)
        father[k][x] = father[k][y];
}
int main()
{
    int n,m,c;
    int u,v,d;
	int i;
 //  freopen("in.txt","r",stdin);
    while( ~scanf("%d%d%d",&n,&m,&c) ){
        init(n);
        while( m-- ){
            scanf("%d%d%d",&u,&v,&d);
            union_set(u,v);
            tree[u].push_back(make_pair(v,d));
            tree[v].push_back(make_pair(u,d));
        }
        for( i = 0; i < c; i++){
            scanf("%d%d",&u,&v);
            if( find(u,1) != find(v,1))continue;
            query[u].push_back(make_pair(v,i));
            query[v].push_back(make_pair(u,i));
        }
        for(  i = 1; i <= n; i++){
            if( !vis[i] )
                LCA(i);
        }
        for( i = 0; i < c; i++)
            if( res[i] == -1)puts("Not connected");
            else printf("%d\n",res[i]);
    }
    return 0;
}


 方法二:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;
const int maxn = 10100;
int anc[maxn],dis[maxn],deep[maxn],vis[maxn],fa[maxn];
vector<pair<int,int> >tree[maxn];
void init(int n)
{
    memset(vis,0,sizeof(vis));
    for( int i = 1; i <= n; i++){
		fa[i] = i;
        tree[i].clear();
    }
}
void dfs(int u,int now_fa,int now_anc,int now_deep,int now_len)
{
	fa[u] = now_fa;
	anc[u] = now_anc;
    vis[u] = u;
    deep[u] = now_deep;
    dis[u] = now_len;
    for( int i = 0; i < tree[u].size() ; i++)
    {
        pair<int,int>x = tree[u][i];
        if( !vis[x.first] )
            dfs(x.first,u,now_anc,now_deep+1,now_len+x.second);
    }
}
int find(int x,int y){
    if( x == y)return x;
    if( deep[x] > deep[y])
    return find(fa[x],y);
    else return find(x,fa[y]);
}
int main()
{
    int n,m,c;
    int u,v,d;
	int i;
    while( ~scanf("%d%d%d",&n,&m,&c)){
		init(n);

        while( m-- ){
            scanf("%d%d%d",&u,&v,&d);
            tree[u].push_back(make_pair(v,d));
            tree[v].push_back(make_pair(u,d));
        }
        for( i = 1; i <= n; i++ )
            if(!vis[i])
                dfs(i,-1,i,0,0);
        for( i = 0; i < c; i++){
            scanf("%d%d",&u,&v);
            if(anc[u] != anc[v])puts("Not connected");
            else printf("%d\n",dis[u]+dis[v] - 2*dis[find(u,v)]);
        }
    }
    return 0;
}


 

 

posted @ 2013-07-26 21:31  一生挚爱  阅读(163)  评论(0编辑  收藏  举报