POJ 1986 Distance Queries(在线LCA)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题目:一棵树,两个点之间的路径
我只是为了SPOJ COT来做一下LCA的。。。
在线的LCA就是,先搞出一个欧拉序列
然后RMQ中间部分,其实就是a到lca(a,b)到b的一棵子树
找到最小深度即可。。
AOJ递归栈太小,只能手写堆栈。。。sad
#include<iostream>  
#include<cstdio>  
#include<map>  
#include<cstring>  
#include<cmath>  
#include<vector>  
#include<algorithm>  
#include<set>  
#include<stack>
#include<string>  
#include<ctime>
#include<queue>  
#define inf 1000000005  
#define M 10000005 
#define N 40005
#define maxn 210005  
#define eps 1e-8
#define zero(a) fabs(a)<eps  
#define Min(a,b) ((a)<(b)?(a):(b))  
#define Max(a,b) ((a)>(b)?(a):(b))  
#define pb(a) push_back(a)  
#define mp(a,b) make_pair(a,b)  
#define mem(a,b) memset(a,b,sizeof(a))  
#define LL long long  
#define MOD 1000000007
#define sqr(a) ((a)*(a))  
#define Key_value ch[ch[root][1]][0]  
#define test puts("OK");  
#define pi acos(-1.0)
#define lowbit(x) ((-(x))&(x))
#define HASH1 1331
#define HASH2 10001
#define C   240  
#define vi vector<int>
#define TIME 10  
#pragma comment(linker, "/STACK:1024000000,1024000000")  
using namespace std;
vector<pair<int,int> >edge[N];
int n,q,dist[N];
int depth=0,b[N*2],a[N*2],tot=0;
int p[N],f[N];
void dfs(){
    stack<pair<int,pair<int,int> > >s;
    s.push(mp(1,mp(0,0)));
    while(!s.empty()){
        pair<int,pair<int,int> >now=s.top();s.pop();
        int u=now.first,pre=now.second.first,i=now.second.second;
        if(i==0){
            int t=++depth;
            b[++tot]=t;
            f[t]=u;
            p[u]=tot;
        }
        if(i<edge[u].size()){
            int v=edge[u][i].first,w=edge[u][i].second;
            s.push(mp(u,mp(pre,i+1)));
            if(v==pre) continue;
            dist[v]=dist[u]+w;
            s.push(mp(v,mp(u,0)));
        }    
        else 
            b[++tot]=b[p[pre]];
    }
}
void dfs(int u,int pre){
    int t=++depth;
    b[++tot]=t;
    f[t]=u;
    p[u]=tot;
    for(int i=0;i<edge[u].size();i++){
        int v=edge[u][i].first,w=edge[u][i].second;
        if(v==pre) continue;
        dist[v]=dist[u]+w;
        dfs(v,u);
        b[++tot]=t;
    }
}
int dp[N*2][20];
void Init_rmq(int n){
    for(int i=1;i<=n;i++)
        dp[i][0]=b[i];
    int m=floor(log(n*1.0)/log(2.0));  
    for(int j=1;j<=m;j++)
        for(int i=1;i<=n-(1<<j)+1;i++)
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);  
}
int rmq(int l,int r){  
    int k=floor(log((r-l+1)*1.0)/log(2.0));  
    return min(dp[l][k],dp[r-(1<<k)+1][k]);  
}  
int lca(int a,int b){
    if(p[a]>p[b]) swap(a,b);
    return f[rmq(p[a],p[b])];
}
int main(){
    //freopen("dquery.2.in","r",stdin);
    scanf("%d%d",&n,&q);
    while(q--){
        int u,v,w;char str[5];
        scanf("%d%d%d%s",&u,&v,&w,str);
        edge[u].pb(mp(v,w));
        edge[v].pb(mp(u,w));
    }
    dist[1]=0;
    //dfs(1,0);
    dfs();
    Init_rmq(tot);
    scanf("%d",&q);
    while(q--){
        int u,v;
        scanf("%d%d",&u,&v);
        printf("%d\n",dist[u]+dist[v]-2*dist[lca(u,v)]);
    }
    return 0;
}


评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值