题目链接: P2391 白雪皑皑
大致题意
有 n n n个位置, 初始每个位置都未被染色(初值为0).
接下来要进行 m m m次染色操作, 第 i i i次把 [ l , r ] [l, r] [l,r]染色为颜色 i i i. (后一次染色会覆盖前一次染色).
问: 最终每个位置的颜色是什么.
解题思路
并查集
由于后面的操作会覆盖掉前面的操作, 因此我们不妨 “倒着”进行染色.
我们如果保证每个位置只被访问一次的话, 这样我们就可以做到线性的复杂度.
我们通过并查集来维护, 对于位置 i i i而言, p [ i ] p[i] p[i]表示 [ i , n ] [i, n] [i,n]区间中下一个该被染色的位置是哪里.
特别的, 我们应当在 n + 1 n + 1 n+1位置设置哨兵, 以避免死循环.
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E6 + 10;
int p[N], col[N];
int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
int main()
{
int n, m, pp, qq; cin >> n >> m >> pp >> qq;
rep(i, n + 1) p[i] = i;
int cou = n; //未被染色的位置
for (int i = m; i >= 1 and cou; --i) {
int l = (i * pp + qq) % n + 1, r = (i * qq + pp) % n + 1;
if (l > r) swap(l, r);
int now = find(l);
while (now <= r) {
col[now] = i, cou--, p[now] = find(now + 1);
now = find(now + 1);
}
}
rep(i, n) printf("%d\n", col[i]);
return 0;
}