【题目描述】
给定一个序列,每次把其中一段区间染成某种颜色,求序列最后的样子。
【题目链接】
BZOJ 2054 疯狂的馒头
【解题思路】
我们考虑倒着进行染色,每次染色时只染 还没有颜色 的位置,即 跳过 之前染过色的位置。
怎样实现跳过的操作呢,我们可以把连在一起的染过色的位置看成一个联通块,用类似并查集的方法维护每个连通块的 右端点 (的下一个位置),这样每次跳过一整个联通块即可。
【AC代码】
#include <cstdio>
#include <algorithm>
const int MAXN = 1000000;
int color[MAXN];
int f[MAXN];
int n, m, p, q;
inline void init(){
for(int i = 0; i <= n; i++){
color[i] = 0;
f[i] = i;
}
}
int find(int x){
return x == f[x] ? x : f[x] = find(f[x]);
}
inline void paint(int l, int r, int x){
for(int i = find(l); i <= r; i = find(i)){
color[i] = x;
f[i] = i + 1;
}
}
int main(){
scanf("%d%d%d%d", &n, &m, &p, &q);
init();
for(int i = m; i; i--){
int l = (i * p + q) % n + 1;
int r = (i * q + p) % n + 1;
if(l > r) std::swap(l, r);
l--, r--;
paint(l, r, i);
}
for(int i = 0; i < n; i++){
printf("%d\n", color[i]);
}
return 0;
}
就是这样啦