1. 程式人生 > >HDU 2586 How far away ?(LCA Tarjan/樹上倍增)

HDU 2586 How far away ?(LCA Tarjan/樹上倍增)

題目:問任意兩個點之間的最短路徑長。

如果用Tarjan做的話,那麼

用LCA算出最近公共祖先lca,長度就是dis[u]+dis[v]-2*dis[lca]

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define eps 1e-8
#define memset(a,v) memset(a,v,sizeof(a))
using namespace std;
typedef long long int LL;
const int MAXL(4*1e4);
const int INF(0x7f7f7f7f);
const int mod(1e9+7);
int dir[4][2]= {{-1,0},{1,0},{0,1},{0,-1}};
struct node
{
    int to;
    int next,w;
} edge[2*MAXL+50];
int head[2*MAXL+50];
int father[MAXL+50];
int ans[MAXL+50];
int dis[MAXL+50];
bool vis[MAXL+50];
int x[MAXL+50],y[MAXL+50];
struct nodee
{
    int ed,id;
} nod;
vector<nodee>v[MAXL+50];
int cnt;

int Find(int x)
{
    if(x!=father[x])
        father[x]=Find(father[x]);
    return father[x];
}

void Join(int x,int y)
{
    int fx=Find(x),fy=Find(y);
    if(fx!=fy)
        father[fy]=fx;
}


void LCA(int u)
{
    vis[u]=true;
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v=edge[i].to,w=edge[i].w;
        if(!vis[v])
        {
            dis[v]=dis[u]+w;
            LCA(v);
            Join(u,v);
        }
    }
    for(int i=0; i<v[u].size(); i++)
    {
        int ed=v[u][i].ed,id=v[u][i].id;
        if(vis[ed]==true)
        {
            int lca=Find(ed);
            ans[id]=lca;
        }
    }
}


void add_edge(int x,int y,int w)
{
    edge[cnt].to=y;
    edge[cnt].next=head[x];
    edge[cnt].w=w;
    head[x]=cnt++;
}

int n,q;

void init()
{
    scanf("%d%d",&n,&q);
    cnt=0;
    memset(head,-1);
    memset(vis,false);
    memset(ans,0);
    memset(dis,0);
    for(int i=0; i<=n; i++)
        v[i].clear();
    for(int i=0; i<=n; i++)
        father[i]=i;
    for(int i=1; i<n; i++)
    {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        add_edge(x,y,w);
        add_edge(y,x,w);
    }
    for(int i=1; i<=q; i++)
    {
        scanf("%d%d",x+i,y+i);
        nod.ed=y[i],nod.id=i;
        v[x[i]].push_back(nod);
        nod.ed=x[i],nod.id=i;
        v[y[i]].push_back(nod);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        dis[1]=0;
        LCA(1);
        for(int i=1; i<=q; i++)
            cout<<dis[x[i]]+dis[y[i]]-2*dis[ans[i]]<<endl;
    }
}

樹上倍增

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define eps 1e-8
#define swap(a,b)  (a=a+b,b=a-b,a=a-b)
#define memset(a,v) memset(a,v,sizeof(a))
using namespace std;
typedef long long int LL;
const int MAXL(4*1e4);
const int INF(0x7f7f7f7f);
const int mod(1e9+7);
int dir[4][2]= {{-1,0},{1,0},{0,1},{0,-1}};
struct node{
    int to,next,w;
    node(){}
    node(int to,int next,int w):to(to),next(next),w(w){}
}edge[2*MAXL+50];
int head[2*MAXL+50];
int depth[MAXL+50];
int dp[MAXL+50][20];
int dis[MAXL+50][20];
bool vis[MAXL+50];
int n,q,cnt;

void init(){
    cnt=0;
    memset(head,-1);
    memset(dp,0);
    memset(depth,0);
    memset(dis,0);
    memset(vis,false);
}

void add_edge(int x,int y,int z){
    edge[cnt]=node(y,head[x],z);
    head[x]=cnt++;
}

void getDepth(int u){
    vis[u]=true;
    for(int i=head[u];~i;i=edge[i].next){
        int to=edge[i].to,w=edge[i].w;
        if(!vis[to]){
            depth[to]=depth[u]+1;
            dis[to][0]=w;
            dp[to][0]=u;
            getDepth(to);
        }
    }
}

void getDp(){
    for(int up=1;(1<<up)<=n;up++){
        for(int i=1;i<=n;i++){
            dp[i][up]=dp[dp[i][up-1]][up-1];
            dis[i][up]=dis[i][up-1]+dis[dp[i][up-1]][up-1];
        }
    }
}

int LCA(int x,int y){
    int ans=0;
    if(depth[x]<depth[y])
        swap(x,y);
    int i=-1;
    while((1<<(i+1))<=depth[x])
        i++;
    for(int j=i;j>=0;j--)
        if(depth[x]-(1<<j)>=depth[y])
            ans+=dis[x][j],x=dp[x][j];
    if(x==y) return ans;
    for(int j=i;j>=0;j--){
        if(dp[x][j]!=dp[y][j]){
            ans+=dis[x][j];
            ans+=dis[y][j];
            x=dp[x][j];
            y=dp[y][j];
        }
    }
    return ans+dis[x][0]+dis[y][0];
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d%d",&n,&q);
        for(int i=1;i<n;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add_edge(x,y,z);
            add_edge(y,x,z);
        }
        depth[1]=1;
        getDepth(1);
        getDp();
        while(q--){
            int x,y;
            scanf("%d%d",&x,&y);
            int ans=LCA(x,y);
            cout<<ans<<endl;
        }
    }
}