1. 程式人生 > 實用技巧 >習題:城市獵人(分析&LCA)

習題:城市獵人(分析&LCA)

題目

思路

很明顯可以對式子進行一個變形\(i=m-gcd(a,b)+1\)

考慮如果對\(a\)\(b\)都進行質因數分解

那麼有\(a=\prod p_i^{a_i},b=\prod p_i^{b_i}\)

那麼\(gcd(a,b)=\prod p_i^{min(a_i,b_i)}\)

如果\(a,b\)直接相連,那麼天數即為\(m-gcd(a,b)+1\)

現在考慮間接相連的情況,假設\(a\)\(c\)相連,\(b\)\(d\)相連

此時明顯兩個是等價的,所以這裡只討論\(a\)\(c\)相連的情況

此時的天數為\(m-gcd(a,c)+1\)

顯然的\(gcd(a,c)\le gcd(a,b)\)

也就指,如果是間接相連,那麼一定不會比直接相連更優

列舉gcd進行連邊即可

程式碼

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
namespace ufs
{
    int fa[1000005];
    void makeset(int n)
    {
        for(int i=1;i<=n;i++)
            fa[i]=i;
    }
    int findset(int x)
    {
        if(fa[x]==x)
            return x;
        return fa[x]=findset(fa[x]);
    }
    void merge(int u,int v)
    {
        u=findset(u);
        v=findset(v);
        if(v==u)
            return;
        fa[u]=v;
    }
}
using namespace ufs;
struct node
{
    int e;
    int w;
};
int n,m,q;
int dep[100005];
int dp_f[100005][25];
int dp_w[100005][25];
vector<node> g[100005];   
void dfs(int u,int fa)
{
    dep[u]=dep[fa]+1;
    for(int i=1;i<=20;i++)
    {
        dp_f[u][i]=dp_f[dp_f[u][i-1]][i-1];
        dp_w[u][i]=max(dp_w[u][i-1],dp_w[dp_f[u][i-1]][i-1]);
    }
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i].e;
        if(v!=fa)
        {
            dp_f[v][0]=u;
            dp_w[v][0]=g[u][i].w;
            dfs(v,u);
        }
    }
}
int lca(int u,int v)
{
    int maxx=-1;
    if(dep[u]>dep[v])
        swap(u,v);
    for(int i=20;i>=0;i--)
    {
        if(dep[u]<=dep[dp_f[v][i]])
        {
            maxx=max(maxx,dp_w[v][i]);
            v=dp_f[v][i];
        }
    }
    if(u==v)
        return maxx;
    for(int i=20;i>=0;i--)
    {
        if(dp_f[u][i]!=dp_f[v][i])
        {
            maxx=max(maxx,dp_w[u][i]);
            maxx=max(maxx,dp_w[v][i]);
            u=dp_f[u][i];v=dp_f[v][i];
        }
    }
    //cout<<"lca:"<<dp_f[u][0]<<'\n';
    return max(maxx,max(dp_w[u][0],dp_w[v][0]));
}
int main()
{

    ios::sync_with_stdio(false);
	freopen("pictionary.in","r",stdin);
	freopen("pictionary.out","w",stdout);
    cin>>n>>m>>q;
    memset(dp_w,-1,sizeof(dp_w));
    makeset(n);
    //cout<<'\n';
    for(int i=m;i>=1;i--)
        for(int j=2;1ll*i*j<=n;j++)
            if(findset(i)!=findset(i*j))
            {
                merge(i,i*j);
                //cout<<i<<' '<<i*j<<' '<<m-i+1<<'\n';
                g[i].push_back((node){i*j,m-i+1});
                g[i*j].push_back((node){i,m-i+1});
            }
    dfs(1,0);
    for(int i=1,u,v;i<=q;i++)
    {
        cin>>u>>v;
        cout<<lca(u,v)<<'\n';
    }
    return 0;
}