JZOJ 5782

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


 

对满足 gcd(a, b) = m - i + 1 的点对连边,由于要求的是最早联通时间,之前已经联通则不管后面的边,我们用并查集维护一下连通性即可

这样最后会变成一棵树,暴力枚举 m - i + 1 的倍数建边即可,树边上记录联通时间

每个询问的答案就是路径 x--lca(x, y)--y 上的边权的最大值

发现根本不用建树,在并查集上按秩合并维护树的形态即可,这样最大深度是 log 级别的,lca 也就不用倍增什么的了 = =

暴力乱搞就行了

由于是用并查及维护的信息,需要及时 findfa 更新必要的信息


代码:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cstdio>
using namespace std;

const int MAXN = 100005;

int n, m, q, blk;
int fa[MAXN], siz[MAXN], d[MAXN], dep[MAXN];

int findfa(int x) {
	if(fa[x] != x) dep[x] = dep[fa[x]] + 1;
	else return x;
	return findfa(fa[x]);
}
inline void link(int x, int y, int v) {
	int fx = findfa(x), fy = findfa(y);
	if(fx == fy) return;
	--blk;
	if(siz[fx] <= siz[fy]) {
		d[fx] = v;
		fa[fx] = fy;
		siz[fy] += siz[fx];
		findfa(fy);
	} else {
		d[fy] = v;
		fa[fy] = fx;
		siz[fx] += siz[fy];
		findfa(fx);
	}
	return;
}
inline int query(int xx, int yy) {
	findfa(xx); findfa(yy);
	if(dep[yy] > dep[xx]) swap(xx, yy);
	int res = 0;
	while(dep[xx] != dep[yy]) {
		res = max(res, d[xx]);
		xx = fa[xx];
	}
	while(xx != yy) {
		res = max(res, max(d[xx], d[yy]));
		xx = fa[xx];
		yy = fa[yy];
	}
	return res;
}

int main() {
	freopen("pictionary.in", "r", stdin);
	freopen("pictionary.out", "w", stdout);
	scanf("%d%d%d", &n, &m, &q);
	blk = n;
	for(int i = 1; i <= n; ++i) {fa[i] = i; siz[i] = 1;}
	for(int i = 1; i <= m; ++i) {
		int cur = m - i + 1, mul = 2, last = m - i + 1;
		while(cur * mul <= n) {
			link(last, cur * mul, i);
			last = cur * mul;
			++mul;
			if(blk == 1) break;
		}
		if(blk == 1) break;
	}
	register int xx, yy;
	while(q--) {
		scanf("%d%d", &xx, &yy);
		printf("%d\n", query(xx, yy));
	}
	return 0;
}

  

 
posted @ 2018-08-08 21:31  EvalonXing  阅读(274)  评论(0编辑  收藏  举报