Description
有n个城市,标号为1到n,修建道路花费m天,第i天时,若gcd(a,b)=m-i+1,则标号为a的城市和标号为b的城市会建好一条直接相连的道路,有多次询问,每次询问某两座城市最早什么时候能连通。
Input
第一行输入三个正整数n,m,q,其中q表示询问个数。
接下来q行,每行两个正整数x,y,表示询问城市x和城市y最早什么时候连通。
Output
输出q行,每行一个正整数,表示最早连通的天数
Sample Input
Input 1
8 3 3
2 5
3 6
4 8
Input 2
25 6 1
20 9
Input 3
9999 2222 2
1025 2405
3154 8949
Sample Output
Output 1
3
1
2
Output 2
4
Output 3
1980
2160
Data Constraint
对于40%的数据,n≤ 1000,q<=100000
对于100%的数据,1 ≤ n,q≤ 100000,1<=m<=q
思路
考试时文件输入输出打错了!!!!!!!!!!!!!!!!!!!
这题让我想起一题叫历史。做法差不多。
开一个并查集,枚举时间,用安置合并,记录每个点加入并查集的时间。
求解时二分时间点,判断这两个点是否在同一集合即可
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100077;
int n,m,q,f[maxn],z[maxn],ti[maxn];
int gf(int x,int t)
{
while(x!=f[x]&&ti[x]<=t) x=f[x];
return x;
}
void init()
{
for(int i=1; i<=n; i++) f[i]=i,z[i]=1;
for(int i=1; i<=m; i++)
{
int p=m-i+1;
int j=2;
while(p*j<=n)
{
int x=gf(p,i),y=gf(p*j,i);
if(x!=y)
{
if(z[x]<z[y])
{
f[x]=y; z[y]+=z[x]; ti[x]=i;
}
else
{
f[y]=x; z[x]+=z[y]; ti[y]=i;
}
}
j++;
}
}
}
int main()
{
freopen("pictionary.in","r",stdin); freopen("pictionary.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
init();
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
int l=1,r=m;
while(l<=r)
{
int mid=(l+r)>>1,u=gf(x,mid),v=gf(y,mid);
if(u==v) r=mid-1;else l=mid+1;
}
printf("%d\n",l);
}
}