题解
- 发现在第i天,1*(m-i+1)、2*(m-i+1)...(n/(m-i+1))*(m-i+1)会相连
- 所以,边数为Σn/i,所以就只有nlogn条边,显然可以存的下
- 可以用并差集的按秩排序,把size小的并到size大的,可以减小一些树的高度
- 然后要记录这条边链接的时间
- 对于查询两个点最早连接时间
- 可以二分出一个时间,然后在并差集上寻找在二分出时间内的两个点的属于哪个并差集里
- 如果在同一个并差集里,说明还可以时间还可以前,否则时间要往后推
代码
1 #include <cstdio>
2 #include <iostream>
3 #include <algorithm>
4 #include <cstring>
5 #include <cmath>
6 using namespace std;
7 const int inf=1000000;
8 int n,m,q,fa[100010],size[100010],day[100010],x,y,u,v,l,r,ans;
9 int getfather(int x,int y)
10 {
11 while (fa[x]!=x&&day[x]<=y) x=fa[x];
12 return x;
13 }
14 void bcj()
15 {
16 for (int i=m;i>=1;i--)
17 for (int j=2;j<=n/i;j++)
18 {
19 int u=getfather(i,m),v=getfather(i*j,m);
20 if (u!=v)
21 {
22 if (size[u]>size[v]) swap(u,v);
23 day[u]=m-i+1;
24 size[v]+=size[u];
25 fa[u]=v;
26 if ((++l)>=n-1) return;
27 }
28 }
29 }
30 int main()
31 {
32 // freopen("pictionary.in","r",stdin);
33 // freopen("pictionary.out","w",stdout);
34 scanf("%d%d%d",&n,&m,&q);
35 for (int i=1;i<=n;i++) fa[i]=i,day[i]=inf,size[i]=1;
36 bcj();
37 for (int i=q;i>=1;i--)
38 {
39 scanf("%d%d",&u,&v);
40 l=0; r=m;
41 while (l<=r)
42 {
43 int mid=(l+r)/2;
44 x=getfather(u,mid),y=getfather(v,mid);
45 if (x==y) ans=mid,r=mid-1; else l=mid+1;
46 }
47 printf("%d
",ans);
48 }
49 return 0;
50 }