2054: 疯狂的馒头
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1092 Solved: 465
[ Submit][ Status][ Discuss]
Description
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
Source
----------------------------------------------------------------
正解:并查集
我觉得这是在用并查集实现链表的功能。
由于最后的染色可以覆盖先前的染色,所以我们在时间上从后往前进行操作。整个馒头是个并查集,一开始每个馒头都指向自己,当让 [l,r] 染成color 时,找到 [l,r] 区间内所有馒头的根,这个根的代表的就是在馒头序列中在这一馒头以右(包括这个馒头)的第一个没被染色的馒头,将它染色就是先将它的颜色记录下来(即 c[i]=color),再将他的父亲设为他的右边的馒头(即 fa[i]=i+1)。这样就完成了。最后还可以判断是否已染了 n 个馒头,若已染了,就循环
有一个比较坑的地方是,在给并查集赋初值时,多赋几个,否则会 RE。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010010;
int n, m, p, q, k;
int fa[N], c[N];
int find(int x){
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
int main(){
scanf("%d%d%d%d",&n,&m,&p,&q);
for(int i=n+2; i>=0; --i) fa[i]=i;
for(int i=m, l, r, j; i; --i){
l = (i*1ll*p+q)%n+1;
r = (i*1ll*q+p)%n+1;
if(l>r) swap(l,r);
for(j=find(l); j<=r; j=find(j)){
c[j]=i; fa[j]=j+1;
if((++k)==n) break;
}
}
for(int i=1; i<=n; ++i) printf("%d\n",c[i]);
return 0;
}