zoukankan      html  css  js  c++  java
  • [jzoj 5782]【NOIP提高A组模拟2018.8.8】 城市猎人 (并查集按秩合并+复杂度分析)

    传送门

    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

    Solution

    可以发现每一天连的边一定是(m-i+1)的倍数且不小于n,那么有个结论就是这些边的总数约为(nlogn)所以我们可以暴力连边,边权为天数
    那么查询的就是两个点到lca路径上的最大边权,考虑按秩合并的并查集,我们知道这个并查集树的深度最大为(logn),所以每次暴力走到lca并找出答案即可

    Code

    //By Menteur_Hxy
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define M(a,b) memset(a,(b),sizeof(a))
    #define F(i,a,b) for(register int i=(a);i<=(b);i++)
    #define R(i,a,b) for(register int i=(b);i>=(a);i--)
    #define E(i,u) for(register int i=head[u];i;i=nxt[i])
    using namespace std;
    
    int read() {
    	int x=0,f=1; char c=getchar();
    	while(!isdigit(c)) {if(c=='-')f=-f; c=getchar();}
    	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    	return x*f;
    }
    
    const int N=100010;
    int n,m,q;
    int fa[N],dis[N],siz[N],dep[N];
    
    int getf(int x) {
    	if(fa[x]==x) return dep[x]=0,x;
    	int father=getf(fa[x]);
    	dep[x]=dep[fa[x]]+1;
    	return father;
    }
    
    void add(int u,int v,int c) {
    	int fu=getf(u),fv=getf(v);
    	if(fu!=fv) {
    		if(siz[fu]>siz[fv]) swap(fu,fv);
    		fa[fu]=fv; siz[fv]=max(siz[fv],siz[fu]+1);
    		dis[fu]=c;
    	}
    }
    
    int main() {
    	freopen("pictionary.in","r",stdin);
    	freopen("pictionary.out","w",stdout);
    	n=read(),m=read(),q=read();
    	F(i,1,n) fa[i]=i,siz[i]=1;
    	F(i,1,m) {
    		int x=m-i+1;
    		for(register int j=1;x*j+x<=n;j++) add(x*j,x*j+x,i);
    	}
    	F(i,1,q) {
    		int x=read(),y=read(),ans=0;
    		getf(x);getf(y);
    		if(dep[x]<dep[y]) swap(x,y);
    		while(dep[x]>dep[y]) ans=max(ans,dis[x]),x=fa[x];
    		while(x!=y) {
    			ans=max(ans,dis[x]),x=fa[x];
    			ans=max(ans,dis[y]),y=fa[y];
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    版权声明:本文为博主原创文章,未经博主允许不得转载。 博主:https://www.cnblogs.com/Menteur-Hxy/
  • 相关阅读:
    Redis学习
    extractor
    Linux fork exec等
    Linux kill 命令
    GCC参数使用
    Shell 参数(2) --解析命令行参数工具:getopts/getopt
    Shell 参数(1)
    shell 中并发执行
    Linux 下新增用户的流程
    Linux 安全rm
  • 原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9445799.html
Copyright © 2011-2022 走看看