Hihocoder 1067 最近公共祖先二

裸的LCA离线算法,存下来当模板用吧。
思想就是,将所有的查询都先存起来,然后对树做一次dfs遍历,对每一次经过的节点进行染色,标记为未访问,正在访问,和已经访问完毕。可以很明显的发现如果当前点是一个查询的端点,那么如果另外一个端点正在访问,则当前点是另外一个端点的子节点,两者的LCA为另外一个端点,如果另外一个端点已经访问完了,那么就往上找最近的正在访问的端点,使得这两个点同时在这个端点的子树中。这里查找的时候用到了并查集路径压缩的思想。
#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 = 2e5 + 10;

int head[maxn], nxt[maxn << 1], v[maxn << 1], ecnt;
int headQ[maxn], nxtQ[maxn << 1], vQ[maxn << 1], idQ[maxn << 1], Qcnt;
int ans[maxn] , n, Q, fa[maxn], col[maxn];
bool hasfa[maxn];
map<string, int> mp;
map<int, string> smp;
char name1[maxn], name2[maxn];

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];
}

int getfa(int u) {
	return u == fa[u] ? u : fa[u] = getfa(fa[u]);
}

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

void addQ(int uu, int vv, int nowid) {
	vQ[Qcnt] = vv; nxtQ[Qcnt] = headQ[uu]; idQ[Qcnt] = nowid; headQ[uu] = Qcnt++;
}


void dfs(int now) {
	//一开始把颜色填为灰色
	col[now] = 1;
	//看看是否有询问可以处理
	for(int i = headQ[now]; ~i; i = nxtQ[i]) {
		if(ans[idQ[i]] != 0) continue;
		int nowv = vQ[i];
		if(col[nowv] == 0) continue;
		if(col[nowv] == 1) ans[idQ[i]] = nowv;
		if(col[nowv] == 2) ans[idQ[i]] = getfa(nowv);
	}
	for(int i = head[now]; ~i; i = nxt[i]) {
		dfs(v[i]);
		//一个节点dfs完了之后,变颜色并且更新父节点
		col[v[i]] = 2;
		fa[v[i]] = now;
	}
}


int main() {
	memset(head, -1, sizeof(head));
	memset(headQ, -1, sizeof(headQ));
	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);
		hasfa[b] = true;
	}
	int root;
	scanf("%d", &Q);
	for(int i = 1; i <= Q; i++) {
		scanf("%s%s", name1, name2);
		int a = getid(name1), b = getid(name2);
		addQ(a, b, i); addQ(b, a, i);
	}
	n = mp.size();
	for(int i = 1; i<= n; i++) if(!hasfa[i]) root = i;
	for(int i = 1; i <= n; i++) fa[i] = i;
	dfs(root);
	for(int i = 1; i <= Q; i++) {
		puts(smp[ans[i]].c_str());
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/rolight/p/4065851.html