SDU 1247 LCA

Castle

  • Time Limit: 1s
  • Memory Limit: 128.0 MB

Description

The cosmic leader Loki is exploring a castle full of treasure. The castle can be considered as a connected undirected graph with 
  
  
   
   N
  
  N

 vertices and 
  
  
   
   N
  
  N

 edges. Teleporting is a common skill
among the dwellers of the Chaobuli star. However before Loki teleports he has to know the distance between the destination point and the starting point. Help Loki find the shortest distance between 
  
  
   
   Q
  
  Q

 pairs of vertices.

Input

The first line contains a single integer 
  
  
   
   T
  
  T

 denoting the number of test cases. 
For each test case, the first line contains two integers 
  
  
   
   N
  
  N

 and 
  
  
   
   Q
  
  Q

 meaning as above. 

  
  
   
   N
  
  N

 lines follow, each containing three integers 
  
  
   
   u,v,w
  
  u,v,w

 meaning there's an undirected edge between vertex 
  
  
   
   u
  
  u

 and vertex 
  
  
   
   v
  
  v

 with weight 
  
  
   
   w
  
  w

. No edges will be given more than once. 
Each of the next 
  
  
   
   Q
  
  Q

 lines contains a pair of vertices 
  
  
   
   u,v
  
  u,v

 denoting a query.

Output

For each test case print 
  
  
   
   Q
  
  Q

 lines, each containing a single integer denoting the shortest distance between the given vertices.

Sample Input 1

1
4 2
0 1 3
1 2 1
2 3 1
3 0 2
1 3
0 2

Sample Output 1

2
3


题意:给出一个包含n个点,n条边的无向图,图中不包含重边。
给出q个询问,每次需要回答从u到v的最短路。保证图联通

题解:图就是一棵树+一条额外边
那么对于每次询问  我们可以查出走这条额外的边的值和不走的值  取个min
对于距离  用rmq预处理出lca  然后o1查询lca

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,head[30005],cnt,tot,dpp[30005];
struct node{
    int to,nex,wei;
}edge[60005];
const int MAXN = 30010;
int F[MAXN*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始
int P[MAXN];//P[i]表示点i在F中第一次出现的位置
void add(int u,int v,int w){
    edge[tot].to=v;
    edge[tot].wei=w;
    edge[tot].nex=head[u];
    head[u]=tot++;
}
int rmq[2*MAXN],pre[MAXN];//rmq数组,就是欧拉序列对应的深度序列
int find(int x){
	if(pre[x]!=x){
		int r=find(pre[x]);
		pre[x]=r;
	}
	return pre[x];
}
struct ST
{
    int mm[2*MAXN];
    int dp[2*MAXN][20];//最小值对应的下标
    void init(int n)
    {
        mm[0] = -1;
        for(int i = 1;i <= n;i++)
        {
            mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
            dp[i][0] = i;
        }
        for(int j = 1; j <= mm[n];j++)
            for(int i = 1; i + (1<<j) - 1 <= n; i++)
                dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
    }
    int query(int a,int b)//查询[a,b]之间最小值的下标
    {
        if(a > b)swap(a,b);
        int k = mm[b-a+1];
        return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
    }
}st;
void dfs(int u,int pre,int dep,int sum)
{
    dpp[u]=sum;
    F[++cnt] = u;
    rmq[cnt] = dep;
    P[u] = cnt;
    for(int i = head[u];i != -1;i = edge[i].nex)
    {
        int v = edge[i].to;
        if(v == pre)continue;
        dfs(v,u,dep+1,sum+edge[i].wei);
        F[++cnt] = u;
        rmq[cnt] = dep;
    }
}
void LCA_init(int root,int node_num)//查询LCA前的初始化
{
    cnt = 0;
    dfs(root,root,0,0);
    st.init(2*node_num-1);
}
int query_lca(int u,int v)//查询u,v的lca编号
{
    return F[st.query(P[u],P[v])];
}
int main(){
    int t,q,i,j;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&q);
        memset(head,-1,sizeof(head));
        for(i=1;i<=n;i++)pre[i]=i;
        cnt=tot=0;
        int u,v,w;
        int us,vs,ws;
        for(i=1;i<=n;i++){
            scanf("%d%d%d",&u,&v,&w);
            u++;
            v++;
            if(find(u)==find(v)){
                us=u;
                vs=v;
                ws=w;
                continue;
            }
            pre[find(u)]=v;
            add(u,v,w);
            add(v,u,w);
        }
        LCA_init(1,n);
        while(q--){
            scanf("%d%d",&u,&v);
            u++;
            v++;
            int zu=query_lca(u,v),ans1,ans2,ans3;
            ans1=dpp[u]+dpp[v]-2*dpp[zu];
            int zu1=query_lca(u,us),zu2=query_lca(v,vs);
            ans2=dpp[u]+dpp[us]-2*dpp[zu1]+dpp[v]+dpp[vs]-2*dpp[zu2]+ws;
            zu1=query_lca(u,vs);
            zu2=query_lca(v,us);
            ans3=dpp[u]+dpp[vs]-2*dpp[zu1]+dpp[v]+dpp[us]-2*dpp[zu2]+ws;
            printf("%d\n",min(ans1,min(ans2,ans3)));
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值