ZOJ 3195 LCA转RMQ

点击打开链接

题意:输入n,接下来n-1行,每行a,b,c代表a与b有一条权值为c的边,双向边,m次询问,问最短的距离使a,b,c可以联通

思路:LCA的模版题,没什么好说的,看理论的话网上好多本弱就不说了,代码有注释,有助于理解

#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=50010;
struct edge{
    int to,cost;
    edge(int a,int b){to=a;cost=b;}
};
vector<edge>G[maxn];
bool vis[maxn];
int L[maxn*2],E[maxn*2],H[maxn],dis[maxn],dp[2*maxn][20];
//H为每个元素第一次出现的位置,E为dfs遍历的序号,L为深度,dis为每个点到根的距离
//dp[i][j]代表的是i到j深度最小的位置
int k,n;
void dfs(int t,int deep){
    k++;E[k]=t;L[k]=deep;H[t]=k;//遍历时叶子在E中只会出现一次,而非叶子节点会出现多次
    for(unsigned int i=0;i<G[t].size();i++){
        edge tt=G[t][i];
        if(!vis[tt.to]){//出现过就不再继续,保证dis的大小和H第一次出现的位置
            vis[tt.to]=1;
            dis[tt.to]=dis[t]+tt.cost;
            dfs(tt.to,deep+1);
            k++;E[k]=t;L[k]=deep;
        }
    }
}
void RMQ_init(){//RMQ的ST算法
    for(int i=1;i<=2*n-1;i++) dp[i][0]=i;
    for(int i=1;(1<<i)<=2*n-1;i++){
        for(int j=1;j+(1<<i)-1<=2*n-1;j++){
            if(L[dp[j][i-1]]<L[dp[j+(1<<(i-1))][i-1]]) dp[j][i]=dp[j][i-1];
            else dp[j][i]=dp[j+(1<<(i-1))][i-1];
        }
    }
}
int RMQ(int le,int ri){
    le=H[le];ri=H[ri];//找到第一次出现的位置
    if(le>ri) swap(le,ri);//le大于ri说明ri在le之前出现,交换
    int kk=0;
    while((1<<(kk+1))<=ri-le+1) kk++;
    if(L[dp[le][kk]]<L[dp[ri-(1<<kk)+1][kk]]) return E[dp[le][kk]];
    else return E[dp[ri-(1<<kk)+1][kk]];//返回的是dp位置的值
}
int main(){
    int q,a,b,c;
    int flag=0;
    while(scanf("%d",&n)!=-1){
        for(int i=0;i<maxn;i++) G[i].clear();
        if(flag==0) flag=1;
        else printf("\n");
        memset(dis,0,sizeof(dis));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n-1;i++){
            scanf("%d%d%d",&a,&b,&c);
            G[a].push_back(edge(b,c));
            G[b].push_back(edge(a,c));
        }
        k=0;vis[0]=1;
        dfs(0,1);RMQ_init();
        scanf("%d",&q);
        while(q--){
            scanf("%d%d%d",&a,&b,&c);
            int ans=dis[a]+dis[b]+dis[c]-(dis[RMQ(a,b)]+dis[RMQ(a,c)]+dis[RMQ(b,c)]);
            //这个画图看一下就能看出来了
            printf("%d\n",ans);
        }
    }
    return 0;
}
时间: 2024-08-24 11:09:35

ZOJ 3195 LCA转RMQ的相关文章

ZOJ 3195 Design the city

倍增法在线LCA..... ZOJ Problem Set - 3195 Design the city Time Limit: 1 Second      Memory Limit: 32768 KB Cerror is the mayor of city HangZhou. As you may know, the traffic system of this city is so terrible, that there are traffic jams everywhere. Now,

HDU 2586 LCA转RMQ

点击打开链接 题意:就是问两个节点间的距离 思路:又切了一道模版水题,不解释了,看不懂变量含义的可以看我写的这篇,解释的比较详细ZOJ 3195 #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; typedef

lca转RMQ

这个博客写得好 1 #include <stdio.h> 2 #include <vector> 3 #include <string.h> 4 using namespace std; 5 const int N = 100000; 6 7 /* 8 lca 转RMQ 9 10 询问u和v的lca 11 我们保存树的遍历序列,那么只要在序列中找到第一次出现u和第一次出现v的位置 12 然后RMQ该区间深度最小的那个点就是u和v的lca了 13 14 那么要保存每个点首

POJ 1330 Nearest Common Ancestors (在线LCA转RMQ)

题目地址:POJ 1330 在线LCA转RMQ第一发.所谓在线LCA,就是先DFS一次,求出遍历路径和各个点深度,那么求最近公共祖先的时候就可以转化成求从u到v经过的点中深度最小的那个. 纯模板题. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h&g

POJ 2763 Housewife Wind LCA转RMQ+时间戳+线段树成段更新

题目来源:POJ 2763 Housewife Wind 题意:给你一棵树 2种操作0 x 求当前点到x的最短路 然后当前的位置为x; 1 i x 将第i条边的权值置为x 思路:树上两点u, v距离为d[u]+d[v]-2*d[LCA(u,v)] 现在d数组是变化的 对应每一条边的变化 他修改的是一个区间 用时间戳处理每个点管辖的区域 然后用线段树修改 线段树的叶子节点村的是根到每一个点的距离 求最近公共祖先没差别 只是堕落用线段树维护d数组 各种错误 4个小时 伤不起 #include <cs

HDU 2586 How far away ? &lt;&lt; LCA转RMQ+ST表 求树上任两点最短距离裸题

此题还有LCA+tarjin离线查询做法,详见这里 关于ST表 解决RMQ问题,dp[i][j]表示从第i位开始长度为(1<<j)的区间的最值 维护的时候采用倍增思想,维护dp[i][j+1]=opt(dp[i][j],dp[i+(1<<j)][j]) 查询的时候,两端点为l,r,则长度len=r-l,寻找一个k,使(1<<k)大于等于len/2,这样就使得 [l,l+(1<<k)]和[r-(1<<k),r]覆盖整个区间 然后此时,就可以直接用s

ZOJ Design the city LCA转RMQ

Design the city Time Limit: 1 Second      Memory Limit: 32768 KB Cerror is the mayor of city HangZhou. As you may know, the traffic system of this city is so terrible, that there are traffic jams everywhere. Now, Cerror finds out that the main reason

lca 在线算法 zoj 3195

题目链接:Design the city 题目大意是对给定3点,求这三个点只之间的最短距离.三个点两两组合求lca:dis[u]+dis[v]-dis[lca];将三个组合值相加除以2即为答案. RMQ算法学习:http://blog.csdn.net/liang5630/article/details/7917702 对于lca->RMQ的转化,可以参看巨巨写的ppt. 欧拉序列:euler[N]; 深度序列:depth[N]; #include <iostream> #include

ZOJ 3195 Design the city(LCA变形)

题意:给定一棵树,求连接三点所需的最短距离. 思路:LCA变形,连接三点的最短距离可以转化为求任意两点距离之和的和再除以二. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #incl