【Lca 線上st演算法】hdu 2586 How far away ?

CN_swords發表於2017-07-08

LCA 線上st演算法
題意: 對於一個圖,n(<=40000)個點,給出n-1條邊(u,v,w,), m(<=200)個詢問給出兩點,問其最短距離
題解: LCA問題(求最近公共祖先問題),線上演算法(對於每個詢問得出答案,相對離線演算法需要得到所有詢問後一次性給出答案)。
以任意一點作為根節點,兩點最短距離為,兩點分別到根節點的距離和減去兩倍的最近公共祖先到根節點的距離。
st演算法: 基於RMQ(dp)的演算法;
dfs預先處理出ver[] (向下遞迴和回溯經過的點),dep[] (同上經過點的深度),first[] (對於ver,點第一次出現在ver[]陣列的位置)。
分別介紹它們的作用:
first[] 可以對於給出的點得到在dep[]上的範圍,[思考dp的過程]這個範圍肯定包含了其同棵樹的根節點(即最近公共祖先)
dep[] 在得到的範圍裡用RMQ尋找裡面最小值的位置(即公共祖先的位置)
ver[] 對於得到的位置只是dep[]陣列上的位置,ver[]是相對位置上對應的點
注意: 1.每個節點可能遍歷兩邊,dep,ver陣列開N*2
2. first[]點在dep[]對應的id,(l,r)誰大誰小還不確定的

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//#pragma comment(linker, "/STACK:102400000,102400000")

const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF=0x3f3f3f3f;
const LL mod = 1e9+7;
const int N = 100000+10;
const int M = 2500000;

struct Node
{
    int to;
    int val;
};
vector<Node> ma[N];     //vector 記錄圖
int dir[N],ver[N],first[N],dep[N];
bool vis[N];
int top;
void dfs(int n,int depth,int dist)  //dfs處理需要陣列
{
    vis[n]=true;
    ver[++top]=n; first[n]=top; dep[top]=depth; dir[n]=dist;
    for(int i = 0; i < ma[n].size(); i++){
        Node temp = ma[n][i];
        if(!vis[temp.to]){
            dfs(temp.to,depth+1,dist+temp.val);
            ver[++top]=n; dep[top]=depth;   //這倆陣列回溯時也需要記錄
        }
    }
}
int dp[N][30];          //代表區間(i,i+(1<<j)-1)的最小值的位置
void ST(int l,int r)   //預處理RMQ的dp陣列
{
    for(int i = l; i <= r; i++)
        dp[i][0]=i;
    for(int i = 1; (1<<i) <= r-l+1; i++){
        for(int j = l; j+(1<<i)-1 <= r; j++){
            int x = dp[j][i-1];
            int y = dp[j+(1<<(i-1))][i-1];
            dp[j][i] = dep[x]<dep[y]?x:y;
        }
    }
}
int RMQ(int l,int r)    //RMQ處理出(l,r)的最小值位置
{
    int k = 0;
    while((1<<(k+1)) <= r-l+1)
        k++;
    int x = dp[l][k];
    int y = dp[r-(1<<k)+1][k];
    return dep[x]<dep[y]?x:y;
}
int LCA(int x,int y)    //將處理出的位置對應其點
{
    int l = first[x];
    int r = first[y];
    if(l > r){int temp = l; l = r; r = temp;}   //(l,r)誰大誰小還不確定的
    int id=RMQ(l,r);
    return ver[id];
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++)
            ma[i].clear();
        for(int i = 1; i < n; i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            Node temp;
            temp.to = v; temp.val = w;
            ma[u].push_back(temp);
            temp.to = u; temp.val = w;
            ma[v].push_back(temp);
        }
        memset(vis,0,sizeof(vis));
        top = 0;
        dfs(1,0,0);
        ST(1,top);
        while(m--){
            int u,v;
            scanf("%d%d",&u,&v);
            int lca = LCA(u,v);
            printf("%d\n",dir[u]+dir[v]-2*dir[lca]);
        }
    }
    return 0;
}

相關文章