zoukankan      html  css  js  c++  java
  • HDU6031:Innumerable Ancestors(二分+倍增数组)

    传送门

    题意

    n个点的图,有n-1条无向边,m个询问,每次询问
    给出两个集合a和b,找到a的一个元素x,b的一个元素y,使得x和y的lca深度最大

    分析

    这道题如果直接暴力做,复杂度为O(mk1k2*n),爆掉
    考虑二分lca的深度,那么进行如下处理,对于深度deep,如果两个集合(a存在元素x,b存在元素y),使得x向上走depth[x]-deep次与y向上走depth[y]-deep次走到的点相同,那么该深度满足条件。具体做法:
    1.统计a数组中每个点向上走depth[i]-deep次到达的点,放入集合中
    2.查询b数组中是否存在点向上走depth[i]-deep次到达集合中的点
    有则返回true,否则返回false

    代码

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<set>
    #include<algorithm>
    using namespace std;
    
    int n,m,k1,k2,a[100100],b[100100];
    vector<int>mp[100100];
    
    #define F(i,a,b) for(int i=a;i<=b;++i)
    #define mem(a,b) memset(a,b,sizeof(a))
    
    int fa[100100],up[100100][20],depth[100100];
    
    void dfs(int u,int pre,int deep)//遍历,标记父亲,深度
    {
        fa[u]=pre;
        depth[u]=deep;
        int num=mp[u].size();
        F(i,0,num-1)if(mp[u][i]!=pre)
        {
            dfs(mp[u][i],u,deep+1);
        }
    }
    void init()//构建后缀数组
    {
        F(i,1,n) up[i][0]=fa[i];
        F(j,1,19)F(i,1,n) up[i][j]=up[up[i][j-1]][j-1];
    }
    int judge(int a,int deep)//返回a的deep深度的祖先
    {
        if(deep<0) return -1;
        if(deep==0) return a;
        for(int i=19;i>=0;--i) if(deep&(1<<i))
        {
            a=up[a][i];
        }
        return a;
    }
    int check(int deep)//判断该深度两个集合是否存在深度相同的两个点
    {
        set<int>s;
        F(i,1,k1)//记录该深度下所有祖先
        {
            int ret=depth[a[i]]-deep;
            int anc=judge(a[i],ret);
            if(anc==-1) continue;
            s.insert(anc);
        }
        F(i,1,k2)//在数组b中找到相同深度下是否存在相同祖先
        {
            int ret=depth[b[i]]-deep;
            int anc=judge(b[i],ret);
            if(anc==-1) continue;
            if(s.count(anc)) return 1;
        }
        return 0;
    }
    
    int main()
    {
        while(scanf("%d %d",&n,&m)!=EOF)
        {
            int u,v;
            F(i,1,n) mp[i].clear();
            F(i,1,n-1)//建图
            {
                scanf("%d %d",&u,&v);
                mp[u].push_back(v);
                mp[v].push_back(u);
            }
            dfs(1,0,0);
            init();
            F(i,1,m)
            {
                int l=1,r=1,ans=0;
                scanf("%d",&k1);
                //printf("%d
    ",n);
                //F(i,1,n) printf("%d%c",depth[i],i==n?'
    ':' ');
                F(i,1,k1) {scanf("%d",a+i);r=max(depth[a[i]],r);}
                //puts("flag");
                scanf("%d",&k2);
                F(i,1,k2) scanf("%d",b+i);
                while(l<=r)//二分深度
                {
                    int mid=(l+r)>>1;
                    if(check(mid)) { ans=mid;l=mid+1; }else r=mid-1;
                }
                printf("%d
    ",ans+1);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    安装和使用Glassfish
    3GP 的 DASH设计原则与标准
    hdu 2686 Matrix 最小费用最大流 或 多线程DP
    [Win32]客户端程序
    二叉查找树中节点的删除。
    Android:获取屏幕完整宽高,包含状态栏
    Django学习总结之五模型
    畸形的从业观
    调试版本和发行版本
    jsp中常见的错误处理(未完待续)
  • 原文地址:https://www.cnblogs.com/chendl111/p/6903197.html
Copyright © 2011-2022 走看看