習題:城市獵人(分析&LCA)
阿新 • • 發佈:2020-11-28
題目
思路
很明顯可以對式子進行一個變形\(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; }