zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    实战DeviceIoControl 之五:列举已安装的存储设备
    在NT中直接访问物理内存
    实战DeviceIoControl 之三:制作磁盘镜像文件
    实战DeviceIoControl 之六:访问物理端口
    程序员的十层楼(转)
    Vista + VS2005 源代码绑定的问题
    敬告天下IT业主
    手动卸载windows服务
    古墓丽影9的截屏
    白领饮食十大“夺命”恶习(转)
  • 原文地址:https://www.cnblogs.com/rolight/p/4065851.html
Copyright © 2011-2022 走看看