• BZOJ 3910 火车 倍增LCA


    本题并不需要并查集,每次查询一次最近公共祖先,并倍增求出需要被新标记的路径。
    这样保证时间复杂度是 O(nlogn)O(nlogn) 的。
    Code:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn = 500000 + 4;
    const int logn  = 21;
    int f[25][maxn], head[maxn], to[maxn << 1], nex[maxn << 1], cnt, n, m, s, dep[maxn];
    bool  tag[maxn];
    long long ans;
    inline void add_edge(int u,int v){
        nex[++cnt] = head[u];
        head[u] = cnt;
        to[cnt] = v;
    }
    void dfs(int u,int fa, int depth)
    {
        f[0][u] = fa, dep[u] = depth;
        for(int v = head[u]; v ; v = nex[v]){
            if(to[v] != fa){
                dfs(to[v], u, depth + 1);
            }
        }
    }
    inline int lca(int a,int b){                         //b向 a 爬
        if(dep[a] > dep[b]) swap(a,b);
        if(dep[a] != dep[b]){
            for(int i = logn;i >= 0; --i)
                if(dep[f[i][b]] >= dep[a]) b = f[i][b];
        }
        if(a == b) return a;
        for(int i = logn;i >= 0; --i)
        {
            if(f[i][a] != f[i][b]) 
            {
                a = f[i][a], b = f[i][b];
            }
        }
        return f[0][a];
    }
    inline void connect(int a, int b){
        if(tag[a] && tag[b]) return ;
        if(dep[a] < dep[b]) swap(a, b);                                  //a 爬向 b
        int A = a;
        if(tag[A])
        {
            for(int i = logn;i >= 0;--i)
                if(tag[f[i][a]] == 1 ) a = f[i][a];
        }
        do
        {
            tag[a] = tag[f[0][a]] = 1;
            a = f[0][a];
        }while(a != b);
    }
    int main(){
        scanf("%d%d%d",&n,&m,&s);
        for(int i = 1;i < n ; ++i){
            int a,b;
            scanf("%d%d",&a,&b);
            add_edge(a,b);
            add_edge(b,a);
        }
        dfs(1, 0, 1);
        for(int i = 1;i <= logn; ++i)
            for(int j = 1;j <= n; ++j)
                f[i][j] = f[i - 1][f[i - 1][j]];
        int pre = s;
        for(int i = 1;i <= m; ++i){
            int cur;
            scanf("%d",&cur);
            int h = lca(pre, cur);
            if(tag[cur] && tag[pre]) continue;                  
            ans +=(long long) dep[cur] + dep[pre] - 2 * dep[h];             
            connect(pre, h);
            connect(cur, h);
            pre = cur;
        }
        printf("%lld",ans);
        return 0;
    }
    
  • 相关阅读:
    罗马数字
    逆序对
    等价串
    郊区春游
    贝壳找房函数最值
    Educational Codeforces Round 45 Editorial
    Codeforces Round #486 (Div. 3)
    checkbox保存和赋值
    oninput和onchange的区别
    cookie路径概念理解
  • 原文地址:https://www.cnblogs.com/guangheli/p/9845100.html
Copyright © 2020-2023  润新知