zoukankan      html  css  js  c++  java
  • Codeforces 519E A and B and Lecture Rooms [倍增法LCA]

    题意:

    给你一棵有n个节点的树,给你m次询问,查询给两个点,问树上有多少个点到这两个点的距离是相等的。树上所有边的边权是1。

    思路:

    很容易想到通过记录dep和找到lca来找到两个点之间的距离,然后分情况讨论。

    一开始困扰我的问题是如果lca不是正中间的点,如何在比较低的复杂度的层面上求解中点。

    倍增法lca不光可以在logn的时间复杂度内查询某两个点的lca,还可以实现在logm的时间复杂度能查询某个节点的第m个父亲节点。

    算法的核心是用二进制的运算来实现查询。

    #include<bits/stdc++.h>
    #define N 100050
    using namespace std;
    int n;
    struct edge{
        int id;
        edge *next;
    };
    edge edges[N<<1];
    edge *adj[N];
    int ednum;
    int dep[N],rt[25][N],siz[N];
    inline void add_Edge(int a,int b){
        edge *tmp=&edges[ednum++];
        tmp->id=b;
        tmp->next=adj[a];
        adj[a]=tmp;
    }
    void dfs(int pos,int deep){
        dep[pos]=deep;
        siz[pos]=1;
        for(edge *it=adj[pos];it;it=it->next){
            if(!dep[it->id]){
                rt[0][it->id]=pos;
                dfs(it->id,deep+1);
                siz[pos]+=siz[it->id];
            }
        }
    }
    void prelca(){
        for(int i=1;i<=20;i++){
            for(int j=1;j<=n;j++){
                rt[i][j]=rt[i-1][j]==-1?-1:rt[i-1][rt[i-1][j]];
            }
        }
    }
    int LCA(int u,int v){
        if(dep[u]<dep[v])swap(u,v);
        for(int i=0;i<21;i++){
            if((dep[u]-dep[v])>>i&1){
                u=rt[i][u];
            }
        }
        if(u==v)return u;
        for(int i=19;i>=0;i--){
            if(rt[i][u]!=rt[i][v]){
                u=rt[i][u];
                v=rt[i][v];
            }
        }
        return rt[0][u];
    }
    int jump(int pos,int num){
        for(int i=0;i<21;i++){
            if(num>>i&1){
                pos=rt[i][pos];
            }
        }
        return pos;
    }
    void solve(int u,int v){
        if(u==v){
            printf("%d
    ",n);
            return;
        }
        if(max(dep[u],dep[v])-min(dep[u],dep[v])&1){
            printf("0
    ");
            return;
        }
        int anc=LCA(u,v);
        //printf("anc=%d
    ",anc);
        if(dep[u]==dep[v]){
            int ans=n;
            ans-=siz[jump(u,dep[u]-dep[anc]-1)];
            ans-=siz[jump(v,dep[u]-dep[anc]-1)];
            printf("%d
    ",ans);
        }
        else{
            int l=dep[u]+dep[v]-2*dep[anc];
            if(dep[u]<dep[v])swap(u,v);
            int ans=siz[jump(u,l/2)];
            ans-=siz[jump(u,l/2-1)];
            printf("%d
    ",ans);
        }
    }
    int main()
    {
        scanf("%d",&n);
        memset(rt,-1,sizeof(rt));
        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,1);
        prelca();
        //printf("*%d
    ",jump(2,0));
        int m;
        scanf("%d",&m);
        for(int  i=1;i<=m;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            solve(a,b);
        }
        return 0;
    }
    /*
    5
    1 5
    1 2
    2 3
    2 4
    5
    1 5
    2 5
    1 1
    2 2
    3 4
    */
  • 相关阅读:
    37. Sudoku Solver(js)
    36. Valid Sudoku(js)
    35. Search Insert Position(js)
    34. Find First and Last Position of Element in Sorted Array(js)
    33. Search in Rotated Sorted Array(js)
    32. Longest Valid Parentheses(js)
    函数的柯里化
    俞敏洪:我和马云就差了8个字
    vue路由传值params和query的区别
    简述vuex的数据传递流程
  • 原文地址:https://www.cnblogs.com/tun117/p/5304642.html
Copyright © 2011-2022 走看看