2021.08.03 BZOJ 疯狂的馒头(并查集)

疯狂的馒头 - 题目 - 黑暗爆炸OJ (darkbzoj.tk)

重点:

1.并查集的神奇运用

2.离线化

题意:

给一个长为n的序列,进行m次操作,每次将一个区间修改为同一个数,之后要求输出每个位置的值。

分析:

用并查集把已经染过色的馒头跳过。

代码如下:

(来自他人)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1001001
using namespace std;
int n,m,p,q;
int a[M];
namespace Union_Find_Set{
    int fa[M];
    int Find(int x)
    {
        if(!fa[x]||fa[x]==x)
            return fa[x]=x;
        return fa[x]=Find(fa[x]);
    }
}
int main()
{
    using namespace Union_Find_Set;
    int i,j;
    cin>>n>>m>>p>>q;
    for(i=m;i;i--)
    {
        int x=((long long)i*p+q)%n+1;
        int y=((long long)i*q+p)%n+1;
        if(x>y) swap(x,y);
        for(j=Find(x);j<=y;j=Find(j))
            a[j]=i,fa[j]=j+1;
    }
    for(i=1;i<=n;i++)
        printf("%d\n",a[i]);
    return 0;
}

(我自己的MLE)

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

const int N=1e6+10;
int n,m,p,q,col[N],fa[N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
int find(int x){
	return (fa[x]==0||fa[x]==x)?fa[x]=x:fa[x]=find(fa[x]);
}

int main(){
	//freopen("3.out","w",stdout);
	n=read();m=read();p=read();q=read();
	//for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=m;i>=1;i--){
		//cout<<"   case 1"<<endl;//
		//int l=(((i%n)*(p%n))%n+q)%n+1;
		//int r=(((i%n)*(q%n))%n+p)%n+1;
		long long l=((long long)i*p+q)%n+1,r=((long long)i*q+p)%n+1;
		//int l=(i*p+q)%n+1,r=(i*q+p)%n+1;
		//cout<<l<<" "<<r<<endl;//
		if(r<l)swap(l,r);
		for(int j=find(l);j<=r;j=find(j)){
			//cout<<"   case 2 "<<j<<endl;
			col[j]=i;
			fa[j]=j+1;
		}
		//for(int k=1;k<=n;k++)cout<<fa[k]<<" ";cout<<endl;//
	}
	for(int i=1;i<=n;i++)cout<<col[i]<<endl;
	return 0;
}
 posted on 2021-08-03 21:01  eleveni  阅读(97)  评论(0)    收藏  举报