1. 程式人生 > >求LCA(最近公共祖先)

求LCA(最近公共祖先)

演算法1:樹上倍增

//HDU 2586
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 40000+5
#define INF 999999999
using namespace std;
int n,m,T,Q,head[maxn],x,y,z,vis[maxn],fa[maxn],cost[maxn],dep[maxn],maxcost[maxn][20],anc[maxn][20];
struct xx{
    int v,next,q;
}b[maxn];

void
add(int u,int v,int q) { b[++m]=(xx){v,head[u],q}; head[u]=m; } int dfs(int t) { vis[t]=1; for (int k=head[t];k!=0;k=b[k].next) if (!vis[b[k].v]) fa[b[k].v]=t,cost[b[k].v]=b[k].q,dep[b[k].v]=dep[t]+1,dfs(b[k].v); } int ST() { for (int i=1;i<=n;i++) { anc[i][0]=fa[i];maxcost[i][0
]=cost[i]; for (int j=1;(1<<j)<=n;j++) anc[i][j]=0; } for (int j=1;(1<<j)<=n;j++) for (int i=1;i<=n;i++) { int a=anc[i][j-1]; anc[i][j]=anc[a][j-1]; maxcost[i][j]=maxcost[i][j-1]+maxcost[a][j-1]; } } int
query(int p,int q) { int ans=0,log; if (dep[p]<dep[q])swap(p,q); for (log=1;(1<<log)<=dep[p];log++);log--; for (int i=log;i>=0;i--) if (dep[p]-(1<<i)>=dep[q]) ans+=maxcost[p][i],p=anc[p][i]; if (p==q) return ans; for (int i=log;i>=0;i--) if (anc[p][i]&&anc[p][i]!=anc[q][i]) { ans+=maxcost[p][i]+maxcost[q][i]; p=anc[p][i];q=anc[q][i] ; } ans+=maxcost[p][0]+maxcost[q][0]; return ans; } int main() { scanf("%d",&T); while (T--) { m=0; memset(head,0,sizeof(head)); memset(fa,0,sizeof(fa)); memset(vis,0,sizeof(vis)); scanf("%d%d",&n,&Q); for (int i=1;i<n;i++) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z); dfs(1); ST(); while (Q--) { scanf("%d%d",&x,&y); printf("%d\n",query(x,y)); } } return 0; }

演算法2:Tarjan

include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 80000+5

using namespace std;
int Q,dis[maxn],T,x,y,z,n,m,num,head[maxn],vis[maxn],fa[maxn],h[maxn],ans[maxn];
struct xx{
    int v,next,q;
}b[maxn];
struct yy{
    int u,v,next,num;
}b2[405];

void add(int u,int v,int q)
{
    b[++m]=(xx){v,head[u],q};
    head[u]=m;
}

void _add(int u,int v,int q)
{
    b2[++num]=(yy){u,v,h[u],q};
    h[u]=num;
}

int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}

int dfs(int t,int val)
{
    dis[t]=val;
    fa[t]=t;
    //vis[t]=1;

    for (int k=head[t];k!=0;k=b[k].next)
    {
        int v=b[k].v;
        if (!vis[v]) vis[v]=1,dfs(v,val+b[k].q),fa[v]=t;
    }
    for (int k=h[t];k!=0;k=b2[k].next)
      if (vis[b2[k].v])
      {
          ans[b2[k].num]=dis[t]+dis[b2[k].v]-(dis[find(b2[k].v)]*2);
      }
      return 0;
}

int main()
{
    scanf("%d",&T);
    while (T--)
    {
        m=num=0;
        memset(head,0,sizeof(head));
        memset(h,0,sizeof(h));
        memset(vis,0,sizeof(vis));
        scanf("%d%d",&n,&Q);
        for (int i=1;i<n;i++) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
        for (int i=1;i<=Q;i++)
        {
            scanf("%d%d",&x,&y);
            _add(x,y,i);
            _add(y,x,i);
        }
        vis[1]=1;dfs(1,0);
        for (int i=1;i<=Q;i++) printf("%d\n",ans[i]);
    }
    return 0;
}

被資料坑得很慘,開始先寫了倍增,陣列只開了40000,但是神奇的A了。So後來寫Tarjan時也只開了40000,一直RE不明所以,找了很久錯QAQ……然後把陣列開了兩倍大(雙向邊)就沒有然後了……