1. 程式人生 > >HDU2586-How far away ?(離線Tarjan + 倍增)

HDU2586-How far away ?(離線Tarjan + 倍增)

Problem Description

There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.

Input

First line is a single integer T(T<=10), indicating the number of test cases.
  For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
  Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.

Output

For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.

Sample Input

 

2

3 2

1 2 10

3 1 15

1 2

2 3

2 2

1 2 100

1 2

2 1

Sample Output

 

10

25

100

100

題意:求兩個節點之間的最短距離。

樹剖可以解決此題,但是程式碼量比較大,就沒有寫。

如果用LCA解決此問題,那麼兩點之間的距離=dis[x]+dis[y]-2*dis[lca]

dis[i]代表 i 到根節點的距離。(此題根節點為1)

lca代表x和y的最近公共祖先。

 

先用離線Tarjan做了一下。

最近在寫倍增的程式碼,為了熟練運用,又寫了兩份倍增的程式碼。

第一個程式碼dis[i]陣列的含義是到根節點的距離。

第二個程式碼dis[x] [i] 代表x到 (x向上2^i個節點)的距離,可以在預處理倍增表的時候處理掉。

 

①Tarjan離線

#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;
    }
}

 

②倍增1

#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];
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]){
            dis[to]=dis[u]+w;
            depth[to]=depth[u]+1;
            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];
}

int LCA(int x,int y){
    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])
            x=dp[x][j];
    if(x==y) return x;
    for(int j=i;j>=0;j--){
        if(dp[x][j]!=dp[y][j]){
            x=dp[x][j];
            y=dp[y][j];
        }
    }
    return dp[x][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 lca=LCA(x,y);
            cout<<dis[x]+dis[y]-2*dis[lca]<<endl;
        }
    }
}

 

②倍增2

 

#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;
        }
    }
}