国庆七连测(一)BREAD

13 篇文章 0 订阅
2 篇文章 0 订阅

【一句话题面】有一段长度为n的序列初始颜色均为0,给定两个参数p和q。有m次染色,第i次染色把(i* p+q)%n+1到(i* q+p)%n+1之间的格子染成颜色i。询问染色后各个点的颜色。


【分析】
此题在线线段树可AC。。。
然后我们来讲一下美妙的离线算法。
这不禁让我们想到了之前的一道模拟题。m次操作将序列中一段染成1。这里我们也可以用同样的方法。
确定染色顺序为从后往前,则所有染过的点都不需要再次染色,直接合并序列即可。
具体上,可以用并查集合并一段染过色,序号为这段区间的左端点。染色时从最右端开始染色,按集合跳跃右指针,每次把集合合并到最左端。最多合并n次区间,有m次询问所以总复杂度为O(n+m)。
因为各种原因,输出需要快写。。。。
Code:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
//#define int long long
using namespace std;
const int maxn=1e6+1000;
int n,m,p,q;
int a[maxn];
int f[maxn];
int find(int x){
	if(f[x]!=x) f[x]=find(f[x]);
	return f[x];
}
inline void print(int x){
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
signed main(){
//	freopen("bread.in","r",stdin);
//	freopen("bread.out","w",stdout);
	cin>>n>>m>>p>>q;
	memset(a,0,sizeof(a));
	for(int i=1;i<=n;i++)
		f[i]=i;
	for(int c=m;c>=1;c--){
		int x,y;
		x=(c*p+q)%n+1,y=(c*q+p)%n+1;
		if(x>y) swap(x,y);
		if(find(x)==find(y)&&a[find(x)]!=0)continue;
		while(x<=y){
			y=find(y);
			if(a[y]==0) a[y]=c,f[y]=find(x);
			y--;
		}
	}
//	for(int i=1;i<=n;i++){
//		printf("%d\n",a[i]);
//	}
	for(int i=1;i<=n;i++){
		print(a[i]);putchar('\n');
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值