Bzoj P2054 疯狂的馒头 | 并查集

题目链接

思路:因为每次染色都会将某些馒头的颜色彻底更改,所以每个馒头的最终的颜色其实是由最后一次染色决定的,那么我们只考虑最后一次染色即可。对此,我们可以从后往前倒着染色,当目前的染色区间中存在白色馒头时,就将其染成当前的颜色,对于已经染过色的馒头则不处理,因为当前这一次染色已经不是其最后一次染色了,其最终颜色已经确定了。

对以上思路,考虑用经过路径压缩优化的并查集来维护在每个馒头右侧的、距离最近的、未染色的馒头的位置,以减小时间复杂度。

总时间复杂度O(m+n)。

代码:

#include<iostream>
#include<cstdio>
    using namespace std;
    int c[1000005],f[1000005];
int find(int x)
{
    if(f[x]==x) return x;
    return f[x]=find(f[x]);//路径压缩 
}
int main()
{
    int n=0,m=0,p=0,q=0;
    scanf("%d%d%d%d",&n,&m,&p,&q);
    for(int i=1;i<=n+1;i++) f[i]=i;//初始化 
    for(int i=m;i>=1;i--)
    {
        int l=(i*p+q)%n+1,r=(i*q+p)%n+1;
        if(l>r) swap(l,r);
        for(int k=l;;)
        {
            int fx=find(k);
            k=f[fx];//向右找最近的未染色的馒头进行染色 
            if(k>r) break;//如果超过了染色区间范围则退出 
            c[k]=i;//染色 
            f[fx]=find(k+1);//向右合并,得出下一个最近的、在右边的未染色馒头的位置(画画图就明白了)            
        }
    }
    for(int i=1;i<=n;i++) printf("%d\n",c[i]);
    return 0;
}

 

posted @ 2018-07-30 00:41  wozaixuexi  阅读(228)  评论(2编辑  收藏  举报