【BZOJ2054】疯狂的馒头(并查集)

2054: 疯狂的馒头

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 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

HINT

Source

[ Submit][ Status][ Discuss]

----------------------------------------------------------------

正解:并查集
我觉得这是在用并查集实现链表的功能。

由于最后的染色可以覆盖先前的染色,所以我们在时间上从后往前进行操作。整个馒头是个并查集,一开始每个馒头都指向自己,当让 [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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值