Hihocoder 最近公用祖先三 在线LCA

在线的LCA算法,dfs遍历整棵树,对于每个点出现的时候都插入到数组中,然后查询两个点的lca就是两个点在数组中最后出现位置间的dep值最小的点,就转化为链上的RMQ问题了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#include <stack>
#include <string>
#include <iostream>
#include <cmath>
#include <climits>

using namespace std;
const int maxn = 1e5 + 10;
int head[maxn], nxt[maxn << 1], v[maxn << 1];
int rpos[maxn], n, Q, cnt, ecnt;
map<string, int> mp;
map<int, string> smp;
char name1[1024], name2[1024];

struct Node {
	int dep, id;
	bool operator < (const Node &x) const {
		return dep < x.dep;
	}
};

Node val[maxn << 1], minv[maxn << 1][30];

void adde(int uu, int vv) {
	v[ecnt] = vv; nxt[ecnt] = head[uu]; head[uu] = ecnt++;
}

int getid(char *str) {
	if(mp.count(str) == 0) {
		int mpz = mp.size();
		mp[str] = mpz + 1;
		smp[mpz + 1] = str;
		return mpz + 1;
	}
	return mp[str];
}

void dfs(int now, int fa, int dep) {
	val[++cnt].dep = dep; val[cnt].id = now;
	for(int i = head[now]; ~i; i = nxt[i]) if(v[i] != fa) {
		dfs(v[i], now, dep + 1);
		val[++cnt].dep = dep; val[cnt].id = now;
	}
	rpos[now] = cnt;
}

void initRMQ() {
	for(int i = 1; i <= cnt; i++) {
		minv[i][0] = val[i];
	}
	for(int j = 1; (1 << j) <= cnt; j++) {
		for(int i = 1; i + (1 << j) - 1 <= cnt; i++) {
			minv[i][j] = min(minv[i][j - 1], minv[i + (1 << (j - 1))][j - 1]);
		}
	}
}

Node query(int l, int r) {
	int k = 0;
	while((1 << (k + 1)) <= r - l + 1) k++;
	return min(minv[l][k], minv[r - (1 << k) + 1][k]);
}

int main() {
	memset(head, -1, sizeof(head));
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%s%s", name1, name2);
		int a = getid(name1), b = getid(name2);
		adde(a, b); adde(b, a);
	}
	dfs(1, -1, 0);
	initRMQ();
	scanf("%d", &Q);
	while(Q--) {
		scanf("%s%s", name1, name2);
		int a = getid(name1), b = getid(name2);
		a = rpos[a]; b = rpos[b];
		if(a > b) swap(a, b);
		Node ret = query(a, b);
		puts(smp[ret.id].c_str());
	}
	return 0;
}

  

时间: 2024-10-11 21:25:52

Hihocoder 最近公用祖先三 在线LCA的相关文章

hihoCoder_#1069_最近公共祖先&#183;三(RMQ-ST模板)

#1069 : 最近公共祖先·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho使用了Tarjan算法来优化了他们的"最近公共祖先"网站,但是很快这样一个离线算法就出现了问题:如果只有一个人提出了询问,那么小Hi和小Ho很难决定到底是针对这个询问就直接进行计算还是等待一定数量的询问一起计算.毕竟无论是一个询问还是很多个询问,使用离线算法都是只需要做一次深度优先搜索就可以了的. 那么问题就来了,如果每次计算都只针对一个询问进行的话

hdu3078 建层次树+在线LCA算法+排序

题意:n个点,n-1条边构成无向树,每个节点有权,Q次询问,每次或问从a->b的最短路中,权第k大的值,/或者更新节点a的权, 思路:在线LCA,先dfs生成树0,标记出层数和fa[](每个节点的父亲节点).在对每次询问,走一遍一次公共祖先路上 的权,保持,快排.n*logn*q #include<iostream> //187MS #include<algorithm> #include<cstdio> #include<vector> using

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

最近公共祖先问题(LCA)模板

最近公共祖先问题(LCA)是求一颗树上的某两点距离他们最近的公共祖先节点,由于树的特性,树上两点之间路径是唯一的,所以对于很多处理关于树的路径问题的时候为了得知树两点的间的路径,LCA是几乎最有效的解法. 首先是LCA的倍增算法.算法主体是依靠首先对整个树的预处理DFS,用来预处理出每个点的直接父节点,同时可以处理出每个点的深度和与根节点的距离,然后利用类似RMQ的思想处理出每个点的 2 的幂次的祖先节点,这就可以用 nlogn 的时间完成整个预处理的工作.然后每一次求两个点的LCA时只要对两个

hdu 5266 pog loves szh III 在线lca+线段树区间优化

题目链接:hdu 5266 pog loves szh III 思路:因为它查询的是区间上的lca,所以我们需要用在线lca来处理,达到单点查询的复杂度为O(1),所以我们在建立线段树区间查询的时候可以达到O(1*nlgn)的时间复杂度 ps:因为栈很容易爆,所以.....你懂的 -->#pragma comment(linker, "/STACK:1024000000,1024000000") /*****************************************

hihocoder1069最近公共祖先&#183;三(LCA在线算法--DFS+RMQ-ST)

树上任意两点的最近祖先,必定就是这两个节点的最短路径上深度最小的那个点. 例如:下图中,节点7和5,其最短路径为7--4--1--5, 这条路径上深度最小的点为节点1,其深度为1.节点1即为节点7和5的LCA. 因此,要找到任意两个节点的LCA,只需要先找到上述最短路径,再找到最短路径中深度最小的点.而这下面所述LCA在线算法所做的事. LCA在线算法描述(以上图为例): 1.获得“最短路径”(并不是真正的一条路径,包含其他节点,但不影响算法的正确性) 采用DFS遍历整棵树,得到以下数据: (1

hihoCoder week17 最近公共祖先&#183;三 lca st表

记录dfs序列,dfn[tot] 记录第tot次访问的节点 然后查两点在dfs序中出现的第一次 id[u] id[v] 然后  找 dep[k] = min( dep[i] ) {i 属于 [id[u], id[v]]} 最后dfn[k] 就是所求.. 感觉弄来弄去 就是 在映射... 无非就是 求一段序列深度最小的节点编号 #include <bits/stdc++.h> using namespace std; const int N = 2e5+10; int n, cnt, tot,

【LCA最近公共祖先】在线离线

[在线] 1.倍增法 现将深度较大的跳至与深度较小的统一深度.预处理$fa[u][i]$表示$u$往上跳$2^i$个单位后的祖先,则就可以像快速幂一样,将移动的步数化为二进制,如果第$i$位为$1$,那么向上跳$2^i$次方,即$if(1 << i \& d) u = fa[u][i]$.跳至统一深度后,若两点重合,则返回两点的任意一个.若不重合,再一个一个一起往上跳,直到重合. 复杂度为$O(N*logN) $ [code]求两点距离 #include<iostream>

hihoCoder #1067 : 最近公共祖先&#183;二 [ 离线LCA tarjan ]

传送门: #1067 : 最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中辈分最低的一个是谁.远在美国的他们利用了一些奇妙的技术获得了国内许多人的相关信息,并且搭建了一个小小的网站来应付来自四面八方的请求. 但正如我们所能想象到的……这样一个简单的算法并不能支撑住非常大的访问量,所以摆在小Hi和小Ho面前的无非两种选择: 其一是