题目大意
有n个城市,标号为1到n,修建道路花费m天,第i天时,若gcd(a,b)=m-i+1,则标号为a的城市和标号为b的城市会建好一条直接相连的道路,有多次询问,每次询问某两座城市最早什么时候能连通。
数据范围
对于40%的数据,n≤ 1000,q<=100000
对于100%的数据,1 ≤ n,q≤ 100000,1<=m<=q
Solution
100%:首先分析一下,我们知道在第i天1 * (m - i + 1)….k * (m - i + 1)会相连,于是总的边数就是
也就是
可以知道这是
级别的,所以可以采取暴力连边,记录一下出现时间,用并查集按秩合并维护,最后询问就是查询两者之间路径的最大值.
时间复杂度:O( )
Code
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e6 + 5;
struct ques
{
int x,y;
}a[N];
struct Edge
{
int to,val,next;
}edge[N << 1];
int n,m,q,x,y,tot;
int Rank[N],fa[N],st[N],depth[N];
int get(int x)
{
return fa[x] == x ? x : get(fa[x]);
}
void link(int x,int y,int w)
{
edge[++tot].val = w;
if (Rank[x] > Rank[y])
{
fa[y] = x;
edge[tot].to = x;
edge[tot].next = st[y];
st[y] = tot;
}
else
{
fa[x] = y;
edge[tot].to = y;
edge[tot].next = st[x];
st[x] = tot;
if (Rank[x] == Rank[y]) Rank[x]++;
}
}
int query(int x,int y)
{
int depx = 0,depy = 0,ret = 0,jx = x,jy = y;
while (fa[jx] != jx) jx = fa[jx],depx++;
while (fa[jy] != jy) jy = fa[jy],depy++;
if (depx < depy) swap(depx,depy),swap(x,y);
while (depx > depy)
{
ret = max(edge[st[x]].val,ret);
x = fa[x];
depx--;
}
if (x == y) return ret;
while (x != y)
{
ret = max(ret,max(edge[st[x]].val,edge[st[y]].val));
x = fa[x],y = fa[y];
}
return ret;
}
int main()
{
freopen("pictionary.in","r",stdin);
freopen("pictionary.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
for (int i = 1 ; i <= n ; i++) fa[i] = i;
for (int i = 1 ; i <= m ; i++)
{
int t = m - i + 1;
for (int j = t + t ; j <= n ; j += t) link(get(t),get(j),i);
}
for (int i = 1 ; i <= q ; i++)
{
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y));
}
fclose(stdin);
fclose(stdout);
return 0;
}