zoukankan      html  css  js  c++  java
  • HDU5266 pog loves szh III

    传送门
    就是简单的ST表问题+ LCA,用ST表预处理好连续区间的LCA,然后进行查询
    注意HDU是多组输入,把相应的值清零即可。
    LCA采用倍增法,lg是常数优化。
    ST表用模板,维护([i,i + 2^j - 1])这个区间的LCA
    时间复杂度为预处理(O(nlogn))
    查询(O(mlogn))

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    using namespace std;
    const int N = 3e5 + 5;
    int st[N][22];
    struct Edge{
        int to, next;
    }e[N << 1];
    int head[N], tot;
    void add(int u, int v){
        e[++tot].to = v;
        e[tot].next = head[u];
        head[u] = tot;
    }
    int depth[N], fa[N][22], lg[N];
    void dfs(int u, int fath) {//初始化fa[u][i]与depth[u]
        fa[u][0] = fath, depth[u] = depth[fath] + 1;
        for(int i = 1; i <= lg[depth[u]]; i++)//定理
            fa[u][i] = fa[fa[u][i - 1]][i - 1];
        for(int i = head[u]; i; i = e[i].next){
            int v = e[i].to;
            if(v != fath)
                dfs(v, u);
        }
    }
    int LCA(int x, int y) {//求两个点的最近公共祖先
        if(depth[x] < depth[y]) swap(x, y);
        while(depth[x] > depth[y])
            x = fa[x][lg[depth[x] - depth[y]] - 1];//到同一深度
        if(x == y) return x;
        for(int k = lg[depth[x]] - 1; k >= 0; k--)//向上跳,一直到LCA的下一个结点
            if(fa[x][k] != fa[y][k])
                x = fa[x][k], y = fa[y][k];
        return fa[x][0];
    }
    int Query(int l, int r){
        int k = log2(r - l + 1);
        return LCA(st[l][k], st[r - (1 << k) + 1][k]);
    }
    int main(){
        int n, m;
        while(~scanf("%d", &n)){
            memset(depth, 0, sizeof(depth));
            memset(head, 0, sizeof(head));
            memset(fa, 0, sizeof(fa));
            tot = 0;
            for(int i = 1; i < n; i++){
                int u, v;
                scanf("%d%d", &u, &v);
                add(u, v); add(v, u);
            }
            for(int i = 1; i <= n; i++){
                st[i][0] = i;
                lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
            }
            dfs(1, 0);
            for(int j = 1; j <= log2(n / 2) + 1; j++)
                for(int i = 1; i + (1 << j) - 1 <= n; i++)
                    st[i][j] = LCA(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
            scanf("%d", &m);
            for(int i = 1; i <= m; i++){
                int l, r;
                scanf("%d%d", &l, &r);
                printf("%d
    ", Query(l, r));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    BZOJ2756:[SCOI2012]奇怪的游戏(最大流,二分)
    AtCoder Grand Contest
    BZOJ2565:最长双回文串(Manacher)
    BZOJ2160:拉拉队排练(Manacher)
    BZOJ3790:神奇项链(Manacher)
    BZOJ2342:[SHOI2011]双倍回文(Manacher)
    BZOJ4887:[TJOI2017]可乐(矩阵乘法)
    BZOJ2555:SubString(SAM,LCT)
    BZOJ1396:识别子串(SAM)
    luogu P1080 国王游戏
  • 原文地址:https://www.cnblogs.com/Emcikem/p/13197316.html
Copyright © 2011-2022 走看看