2054: 疯狂的馒头
Time Limit: 10 Sec Memory Limit: 162 MBDescription
Input
第一行四个正整数N,M,p,q
Output
一共输出N行,第i行表示第i个馒头的最终颜色(如果最终颜色是白色就输出0)。
Sample Input
4 3 2 4
Sample Output
2
2
3
0
2
3
0
HINT
这题很好的体现了并查集的使用,因为之前才做了另一道并查集的题目,也是很经典(当时是看了题解),然后做这题,一下就想到用并查集。
首先从后向前涂色,第M次到第1次,因为覆盖了就不算了。
用并查集来维护现在这个点是不是已经涂过了,如果涂过就向它右边的点连边,使右边的点成为它的father,目的是可以根据root操作来快速向右移动到没有涂色的点(向左的话容易RE,因为0结点需要处理一下。)
Code:
2397209 | 2054 | Accepted | 40260 kb | 2216 ms | C++/Edit | 925 B | 2017-11-02 18:26:43 |
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max = 1000000;
int N, M, P, Q;
int fa[Max + 5], vis[Max + 5];
int root(int x){
if(fa[x] == x) return x;
return fa[x] = root(fa[x]);
}
int main(){
scanf("%d%d%d%d", & N, & M, & P, & Q);
int in = 0;
for(int i = 1; i <= N; ++ i) fa[i] = i;
fa[N + 1] = N + 1;
for(int i = M; i && in < N; -- i){
int l = (i * P + Q) % N + 1, r = (i * Q + P) % N + 1;
if(l > r) swap(l, r);
int j = root(l);
while(j <= r && in < N){
vis[j] = i, ++ in;
fa[j] = j + 1;
if(vis[j]) j = root(j);
}
}
for(int i = 1; i <= N; ++ i) printf("%d\n", vis[i]);
return 0;
}