zoukankan      html  css  js  c++  java
  • 【hihoCoder第十七周】最近公共祖先·三

    之前就写的是离线算法。思路就是先序一遍树,记录层数,然后高效RMQ就好。ST和线段树都能过。

    以后有时间将之前的在线算法补上。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define MAXN 100005
    #define MAXM 105
    #define inf 0x7ffffff
    int n;
    struct Edge {
        int v, next;
    } edge[MAXN];
    int head[MAXN];
    int e;
    
    void addEdge(int u, int v) { //加边
        edge[e].v = v;
        edge[e].next = head[u];
        head[u] = e++;
    }
    int first[MAXN];//结点在搜索顺序数组中最先出现的位置(下标)
    int occur[MAXN << 1]; //结点在出现的顺序数组重复的也要记录
    int depth[MAXN << 1]; //结点在搜索树中的深度,与occur相对应
    int dp_min[MAXN << 1][20]; //dp_min[i][j] 表示从第i个位置开始的2^j个元素中的最小值的下标
    int m = 0; //不断记录出现的下标
    
    void dfs(int u, int deep) {
        occur[++m] = u; //进入该点时进行记录
        depth[m] = deep;
        if(!first[u])
            first[u] = m;
        for(int i = head[u]; i + 1; i = edge[i].next) {
            dfs(edge[i].v, deep + 1);
            occur[++m] = u; //访问子树返回也要标记
            depth[m] = deep;
        }
    }
    void init() {
        memset(head, -1, sizeof(head));
        e = 0;
    }
    
    void RMQ_init(int num) {
        for(int i = 1; i <= num; i++)
            dp_min[i][0] = i; //注意dp_min存的不是最小值,而是最小值的下标
        for(int j = 1; j < 20; j++)
            for(int i = 1; i <= num; i++) {
                if(i + (1 << j) - 1 <= num) {
                    dp_min[i][j] = depth[dp_min[i][j - 1]] < depth[dp_min[i + (1 << (j - 1))][j - 1]] ? dp_min[i][j - 1] : dp_min[i + (1 << (j - 1))][j - 1];
                }
            }
    }
    
    int RMQ_min(int a, int b) {
        int l = first[a], r = first[b]; //得到区间左右端点
        if(l > r) {
            int t = l;
            l = r;
            r = t;
        }
        int k = (int)(log(double(r - l + 1)) / log(2.0));
        int min_id = depth[dp_min[l][k]] < depth[dp_min[r - (1 << k) + 1][k]] ? dp_min[l][k] : dp_min[r - (1 << k) + 1][k]; //最小值下标
        return occur[min_id];//取得当前下标表示的结点
    }
    
    map<string, int> Hash_zh;
    map<int, string> Hash_fa;
    
    int main() {
        int t, a, b;
        init();
        m = 0;
        memset(first, 0, sizeof(first));
        bool in[MAXN];//记录结点有无入度
        memset(in, false, sizeof(in));
        int u = 0, v = 0, cnt = 1;
        string str_u, str_v;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) { //注意此题只有n-1条边
            cin >> str_u >> str_v;
            if (Hash_zh[str_u] == 0) {
                Hash_fa[cnt] = str_u;
                Hash_zh[str_u] = cnt ++;
            }
            if (Hash_zh[str_v] == 0) {
                Hash_fa[cnt] = str_v;
                Hash_zh[str_v] = cnt ++;
            }
            u = Hash_zh[str_u];
            v = Hash_zh[str_v];
            addEdge(u, v); //u->v单向
            //in[v] = true;
        }
        dfs(1, 0);
        RMQ_init(m);
        int op_n;
        scanf ("%d", &op_n);
        while (op_n --) {
            cin >> str_u >> str_v;
            if (str_u == str_v) {
                cout << str_u << endl;
                continue;
            }
            u = Hash_zh[str_u];
            v = Hash_zh[str_v];
            cout << Hash_fa[RMQ_min(u, v)] << endl;
        }
    
        return 0;
    }
  • 相关阅读:
    svm 中采用自动搜索参数的方式获得参数值
    OpenCV中的SVM参数优化
    openCV训练程序申请内存不足
    opencv计算运行时间
    马氏距离(Mahalanobis distance)
    Azure网络排查基本梳理
    让Flow成为获取信息的利器(1)
    Azure VM培训简要总结和学习材料梳理
    Powershell利用$_变量批量部署Azure虚拟机
    Azure存储基本介绍
  • 原文地址:https://www.cnblogs.com/Destiny-Gem/p/4058386.html
Copyright © 2011-2022 走看看