hdu2586(最近公共祖先-两种方法实现)

这道题题意是,给定一棵树,每条边都有一定的权值,q次询问,每次询问某两点间的距离。这样就可以用LCA来解,首先找到u, v 两点的lca,然后计算一下距离值就可以了。这里的计算方法是,记下根结点到任意一点的距离dis[],这样ans = dis[u] + dis[v] - 2 * dis[lca(v, v)]了,这个表达式还是比较容易理解的。。

离线复杂度:O(n+m)

在线复杂度:O(nlgn+mlgn)

显然离线的算法有优势!!!!!!!!(在线算法的思想很好)

法一(离线法):LCA Tarjan算法--模版:

http://www.cnblogs.com/sbaof/articles/3338961.html

 

我的修改版(自己的更好!):

//#pragma comment(linker, "/STACK:102400000")
#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<vector>
#define tree int o,int l,int r
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define lo o<<1
#define ro o<<1|1
#define ULL unsigned long long
#define LL long long
#define pb push_back
#define mp make_pair
#define inf 0x7fffffff
#define eps 1e-7
#define N 40009
#define M 209
using namespace std;
int m,n,T,t,x,y;
int dist[N],f[N];
int vis[N];
vector<pair<int,int> >g[N];
vector<pair<int,int> >q[N];
int u[M],v[M],fa[M];
int find(int x)
{
    return x==f[x]?x:f[x]==find(f[x]);
}
void tarjan(int u)//求fa,dist,改f值
{
    f[u]=u;
    vis[u]=1;
    for(int i=0;i<q[u].size();i++)
    {
        int v=q[u][i].first;
        int sub=q[u][i].second;
        if(vis[v])
        {
            fa[sub]=find(v);//find(v)不是f[v]
        }
    }
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i].first;
        int len=g[u][i].second;
        if(!vis[v])//非父节点
        {
            dist[v]=dist[u]+len;
            tarjan(v);
            f[v]=u;//遍历完其子节点再改
        }
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("ex.in","r",stdin);
#endif
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<=n; i++)
        {
            g[i].clear();
            q[i].clear();
        }
        memset(vis,0,sizeof(vis));
        for(int i=1; i<n; i++)
        {
            scanf("%d%d%d",&x,&y,&t);
            g[x].pb(mp(y,t));
            g[y].pb(mp(x,t));
        }
        for(int i=0; i<m; ++i)
        {
            scanf("%d%d",&u[i],&v[i]);
            q[u[i]].pb(mp(v[i],i));
            q[v[i]].pb(mp(u[i],i));
        }
        dist[1]=0;
        tarjan(1);
        for(int i=0;i<m;i++)
        printf("%d\n",dist[u[i]]+dist[v[i]]-2*dist[fa[i]]);
    }
    return 0;
}

 法二(在线法):

http://www.cnblogs.com/sbaof/articles/3338967.html

我的修改版:

//#pragma comment(linker, "/STACK:102400000")
#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<cmath>
#include<list>
#include<queue>
#include<vector>
#define tree int o,int l,int r
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define lo o<<1
#define ro o<<1|1
#define pb push_back
#define mp make_pair
#define ULL unsigned long long
#define LL long long
#define inf 0x7fffffff
#define eps 1e-7
#define N 40009
using namespace std;
int m,n,T,t,x,y;
vector<pair<int,int> >g[N];
int u[N],v[N],c[N],dist[N];
int p[N][20];
const int mc=18;
void init()
{
    for(int i=0; i<=n; i++)
    {
        g[i].clear();
    }
    memset(p,-1,sizeof(p));//初始化!!
}
void dfs(int u,int fa)
{
    for(int i=0; i<g[u].size(); i++)
    {
        int v=g[u][i].first;
        int len=g[u][i].second;
        if(v!=fa)
        {
            dist[v]=dist[u]+len;
            c[v]=c[u]+1;
            p[v][0]=u;
            for(int i=1; i<mc&&p[v][i-1]!=-1; i++)
                p[v][i]=p[p[v][i-1]][i-1];
            dfs(v,u);
        }
    }
}
int lca(int a,int b)
{
    if(c[a]>c[b])
        swap(a,b);
    int t=c[b]-c[a];//WA
    for(int i=0; t&&i<mc; i++)//
        if(t&(1<<i))
        {
            b=p[b][i];
            t^=(1<<i);
        }
    if(a!=b)
    {
        for(int i=mc-1; i>=0; i--)
        {
            if(p[a][i]!=p[b][i])
                a=p[a][i],b=p[b][i];
        }
        a=p[a][0];
    }
    return a;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("ex.in","r",stdin);
#endif
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i=1; i<n; i++)
        {
            scanf("%d%d%d",&x,&y,&t);
            g[x].push_back(mp(y,t));
            g[y].push_back(mp(x,t));
        }
        for (int i=0; i<m; ++i )
        {
            scanf("%d%d",&u[i],&v[i]);
        }
        dist[1]=0;
        c[1]=0;
        dfs(1,-1);
        for(int i=0; i<m; ++i)
            printf("%d\n",dist[u[i]]+dist[v[i]]-dist[lca(u[i],v[i])]*2);
    }
    return 0;
}

 

posted @ 2013-09-24 21:49  baoff  阅读(233)  评论(0编辑  收藏  举报