• MMSet2-【树的直径+LCA】


    题意

    给定一棵 (n) 个节点的树,点编号为 (1...n)(Q) 次询问,每次询问给定一个点集 (S),令 (f(u)=maxlimits_{vin S}dist(u,v)) ,你需要求出(minlimits_{u=1...n}f(u))。其中 (dist(u,v)) 表示树上路径 ((u,v)) 的边数。

    链接:https://ac.nowcoder.com/acm/contest/7141/A

    分析

    题意转化为找出一个点,使得其到点集中的点的距离的最大值最小。对于点集组成的树而言,该点肯定在其直径的中点左右,那么答案就是 (lceil frac{直径}{2} ceil)。因此,需要求出直径的长度。因为点集中深度最深的点一定是直径的一个端点,因此,只要找到该点,然后遍历其它的点,通过 (LCA) 求出两点间距离,取最大值即可。

    (LCA) 通过 (ST) 表实现,这样可以实现 (O(1)) 查询,用倍增可能会超时。

    代码

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N=3e5+5;
    const int M=1e6+6;
    const int mak=25;
    vector<int>pic[N];
    int depth[N],f[N<<1][mak],rnk[N],n,cnt;
    int s[M];
    void read(int &x)
    {
        x=0;
        int f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        x*=f;
    }
    void dfs(int u,int p,int d)
    {
        depth[u]=d;
        rnk[u]=++cnt;
        f[cnt][0]=u;
        for(int i=0;i<pic[u].size();i++)
        {
            int v=pic[u][i];
            if(v==p) continue;
            dfs(v,u,d+1);
            f[++cnt][0]=u;
        }
    }
    void init()
    {
        dfs(1,0,0);
        int len=(int)log2(1.0*cnt);
        for(int k=1;k<=len;k++)
        {
            for(int i=1;i+(1<<k)-1<=cnt;i++)
            {
                int a=f[i][k-1],b=f[i+(1<<(k-1))][k-1];
                if(depth[a]<depth[b]) f[i][k]=a;
                else f[i][k]=b;
            }
        }
    }
    int lca(int u,int v)
    {
        int l=rnk[u],r=rnk[v];
        if(l>r) swap(l,r);
        int len=(int)log2(1.0*(r-l+1));
        int a=f[l][len],b=f[r-(1<<len)+1][len];
        if(depth[a]<depth[b]) return a;
        else return b;
    }
    int get_dis(int u,int v)
    {
        return depth[u]+depth[v]-2*depth[lca(u,v)];
    }
    int main()
    {
        int x,y,m,q;
        read(n);
        for(int i=1;i<n;i++)
        {
            read(x),read(y);
            pic[x].pb(y);
            pic[y].pb(x);
        }
        init();
        read(q);
        while(q--)
        {
            read(m);
            int ans=0,dm=0,d=0;
            for(int i=1;i<=m;i++)
            {
                read(s[i]);
                if(depth[s[i]]>dm)
                    dm=depth[s[i]],d=s[i];
            }
            for(int i=1;i<=m;i++)
            {
                if(s[i]==d) continue;
                ans=max(ans,get_dis(d,s[i]));
            }
            printf("%d
    ",(ans+1)/2);
        }
        return 0;
    }
    
  • 相关阅读:
    Yantai
    Star War
    douban's woshang
    cannot change font's type in coreldraw
    LuXun said
    WaiTan
    free ubuntu disk前天就收到了寄来的光盘
    Winter Swimming
    before buy laptop买本本前,先来看看
    ubuntu beginer
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/13532109.html
Copyright © 2020-2023  润新知