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     那么要保存每个点首次出现的位置
 15     还要保存遍历序列的dep序列,然后RMQ dep序列得到哪一位置的dep最小
 16     然后映射为结点
 17 */
 18
 19 vector<int> g[N];
 20 int total;
 21 int id[N];
 22 int dep[N];
 23 int ref[N];
 24 int dp[N][30];
 25 int pos[N][30];
 26 void dfs(int u, int fa, int d)
 27 {
 28     id[u] = ++total;
 29     dep[total] = d;//去
 30     ref[total] = u;
 31     for(int i=0;i<g[u].size(); ++i)
 32     {
 33         int v = g[u][i];
 34         if(v==fa)continue;
 35         dfs(v,u,d+1);
 36         dep[++total] = d;//回来
 37         ref[total] = u;
 38     }
 39
 40 }
 41
 42 void init()
 43 {
 44     int n = total;
 45     for(int i=1;i<=n;++i)
 46         dp[i][0] = i;
 47
 48
 49     for(int j=1;(1<<j)<=n;++j)
 50     {
 51         for(int i=1;i+(1<<j)-1<=n;++i)
 52         {
 53             int a = dp[i][j-1];
 54             int b = dp[i+(1<<(j-1))][j-1];
 55             if(dep[a] < dep[b])
 56                 dp[i][j] = a;
 57             else
 58                 dp[i][j] = b;
 59         }
 60     }
 61 }
 62 int query(int u, int v)
 63 {
 64     if(id[u] > id[v])
 65         swap(u,v);
 66     int L = id[u];
 67     int R = id[v];
 68     int k = 0;
 69     while(1<<(k+1)<=R-L+1)k++;
 70     int a = dp[L][k];
 71     int b = dp[R-(1<<k)+1][k];
 72     if(R[a]<R[b])
 73     {
 74         return ref[a];
 75     }
 76     else
 77         return ref[b];
 78 }
 79 int main()
 80 {
 81     int n;
 82     while(scanf("%d",&n)!=EOF)
 83     {
 84         for(int i=1;i<=n;++i)
 85             g[i].clear();
 86         int u,v;
 87         for(int i=1;i<n;++i)
 88         {
 89             scanf("%d%d",&u,&v);
 90             g[u].push_back(v);
 91             g[v].push_back(u);
 92         }
 93         total = 0;
 94         dep[1] = 1;
 95         dfs(1,-1,1);
 96         init();
 97         int m;
 98         scanf("%d",&m);
 99         while(m--)
100         {
101             scanf("%d%d",&u,&v);
102             printf("%d\n",query(u,v));
103         }
104     }
105     return 0;
106 }
时间: 2024-10-12 16:01:53

lca转RMQ的相关文章

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和RMQ题目汇总

1.HDU 3183 <span style="color:#000099;">A Magic Lamp Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1624    Accepted Submission(s): 628 Problem Description Kiki likes traveling. One

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 <

HDU 2874 LCA转RMQ+并查集

点击打开链接 题意:问两个城市是否相连,不相连输出Not connected,否则输出两个城市间的最短距离 思路:用并查集判断两个城市的连通性,如果联通则做法和LCA一样,但是注意的一点是地图不连通的话,我们要将所有点都建起来,就要加一个模拟的点,将所有图串起来,很好处理的,看一下就会了 #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include

POJ 1470 Closest Common Ancestors (在线LCA转RMQ)

题目地址:POJ 1470 LCA模板题..输入有点坑,还有输入的第一个结点不一定是根节点. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include

HDU 4836 LCA转RMQ

点击打开链接 题意:中文 思路:如果没有多次询问的话,就可以直接用简单的DFS与LCA就可以完成,然而却多加了个变换根的操作,那么怎么办,与刚刚写的那道点这里类似,都是可以变根的,建议先写那道再写这个,思想都是一样的,那么这道题我们也是以1为根先进行LCA与DFS,然后每次的根与询问就是那道题的换根的部分,这不太好说只能自己理解了 #include <vector> #include <stdio.h> #include <string.h> #include <