习题:城市猎人(分析&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;
}

浙公网安备 33010602011771号