Miraclys

一言(ヒトコト)

洛谷P1196 [NOI2002]银河英雄传说

\(\Large\textbf{Description: } \large{30000个战舰,有两种操作,共k次(k \leq 500005):}\\\)
\(\quad\quad\large{M(i,j):把以i战舰为首的舰队接到j号战舰所在舰队尾部。\\}\)
\(\quad\quad\large{C(i,j):如果战舰i与战舰j在一个舰队,则输出他们间的战舰数;否则,输出-1。\\}\)

\(\Large\textbf{Solution: } \large{对于第一个操作,我们可以想到用并查集维护。\\对于第二个操作,考虑到询问次数很多,我们发现可以用前缀和做到O(1)查询,\\用top数组维护每个战舰与舰首之间的战舰数,那么ans = abs(top[i] - top[j]) - 1。\\考虑如何维护前缀和,因为每次移动都是整个舰队移动,所以舰队中每艘战舰与舰首之间的战舰数不变。如果i与j本来就在一个舰队,那么对我们的top没影响。\\如果一开始i与j并不在一个舰队里呢?对于一个i我们发现在find函数中可以顺便维护他的top数组,其余的战舰对结果没影响,我们不用处理。\\}\)

\(\Large\textbf{Code: }\)

#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
#define LL long long
#define gc() getchar()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 3e4 + 5;
int n, f[N], size[N], top[N];

inline int read() {
	char ch = gc();
	int ans = 0;
	while (ch > '9' || ch < '0') ch = gc();
	while (ch >= '0' && ch <= '9') ans = (ans << 1) + (ans << 3) + ch - '0', ch = gc();
	return ans;	
}

inline int find(int x) {
	if (f[x] == x) return f[x];
	int ff = find(f[x]);
	top[x] += top[f[x]];
	return f[x] = ff;	
}

int main() {
	n = read();		
	rep(i, 1, N) f[i] = i, size[i] = 1, top[i] = 0;
	char s;
	int x, y, no = -1;
	while (n--) {
		cin >> s;
		x = read(), y = read();
		int fx = find(x), fy = find(y);
		if (s == 'M') {
			top[fx] += size[fy]; 
			size[fy] += size[fx];
			f[fx] = fy;
			size[fx] = 0;
		}
		else {
			if (fx != fy) printf("-1\n");
			else printf("%d\n", abs(top[x] - top[y]) - 1);
		}	
	}
	return 0;
}
posted @ 2020-02-24 12:06  Miraclys  阅读(130)  评论(1编辑  收藏  举报

关于本博客样式

部分创意和图片借鉴了

BNDong

的博客,在此感谢