【JZOJ A组】【NOIP提高A组模拟2018.8.8】 城市猎人

16 篇文章 0 订阅
12 篇文章 0 订阅

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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值