bread
【问题描述】
今有N 个无色积木,M 次染色,每次将连续一段积木刷成某种同样的颜色。
每个积木的最终颜色为他最后一次被刷出的颜色。
如果积木从头到尾没有被粉刷过,那么他最终仍然是无色。
在第i 次染色操作中,把第(ip+q)mod N + 1 个积木和第(iq+p) mod N + 1 个积木之间的
所有积木刷成颜色i
求每个积木的最终颜色
【输入格式】
第一行四个正整数N, M, p, q.
【输出格式】
输出N 行,第i 行表示第i 块积木的最终颜色(如果最终无色则输出0)。
【样例输入】
4 3 2 4
【样例输出】
2
2
3
0
【数据规模与约定】
20% n<=1e3 m<=1e4
40% n<=1e4 m<=1e5
60% n<=5e4 m<=5e5
80% n<=3e5 m<=3e6
100% n<=1e6 m<=1e7
mp+q,mq+p 在int 范围内
题面:给一些元素,每次给一些区间染色,颜色为这次染色的序数,区间是((ip+q)%n,(0q+p)%n)),求最后染色完每个区间的颜色.
这道题大家都在喊线段树线段树,可我实在没觉得有必要第一题就打线段树
于是仔细想了一下发现和之前的有一次的第三题很像,所以就打了并查集
其实并查集只是优化了暴力
首先我们发现
(np+q)%n 和(0p+q)%n 的值是一样的,所以会形成一个换,就把m优化到了n,
然后就从后往前做起,我们每处理一个区间,给每一个点设置一个祖先值,全部赋值成最左边这个元素,这样如果下一次还扫到这个区间任意一个点,我们可以直接跳到最左边,省了不少时间。然后再并查集就可以省更多时间了。
注意一开始区间会交错
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
struct color
{
int l,r;
} co[maxn*10];
int a[maxn],n,m,p,q,le[maxn],ans[maxn];
inline int find(int x)
{
if(le[x]==x) return x;
return le[x]=find(le[x]);
}
inline void write(int x)
{
static int stk[100],top=0;
if (x==0) {putchar('0'); return;}
if (x<0) {putchar('-'); x=-x;}
while (x) {stk[++top]=x%10; x/=10;}
while (top) putchar(stk[top--]+'0');
}
int main()
{
//freopen("bread.in","r",stdin);
//freopen("bread.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&p,&q);
for (int i=max(m-n+1,1); i<=m; i++)
{
co[i].l=min((i*p+q)%n+1,(i*q+p)%n+1);
co[i].r=max((i*p+q)%n+1,(i*q+p)%n+1);
}
for (int i=1; i<=n; i++) le[i]=i;
for (int i=m; i>=max(m-n+1,1); i--)
{
int x=co[i].l,y=co[i].r;
int j=y;
while (j>=x)
if (ans[j]==0) {ans[j]=i; le[j]=find(x); j--;}
else {j=le[j]-1;}
}
for (int i=1; i<=n; i++)
write(ans[i]),puts("");
}
线段树
# include<iostream>
# include<cstdio>
# include<cstring>
using namespace std;
const int MAXN=1e6+10;
int f[3*MAXN],opl,opr,opx;
int n,m,p,q,ans[MAXN];
inline void update(int x,int l,int r)
{
if (f[x]!=0) return;
if (opl<=l&&r<=opr) f[x]=opx;
if (l==r) return;
int mid=(l+r)/2;
if (opl<=mid) update(2*x,l,mid);
if (opr>mid) update(2*x+1,mid+1,r);
}
inline void get(int x,int l,int r)
{
if (l==r) { ans[l]=f[x]; return;}
int mid=(l+r)/2;
get(2*x,l,mid);
get(2*x+1,mid+1,r);
}
void print(int x)
{
if(x>9) print(x/10);
putchar(x%10+'0');
}
int main()
{
scanf("%d%d%d%d",&n,&m,&p,&q);
memset(f,0,sizeof(f));
for (int i=m;i>=1;i--) {
opl=(i*p+q)%n+1;
opr=(i*q+p)%n+1;
if (opl>opr) swap(opl,opr);
opx=i;
update(1,1,n);
}
get(1,1,n);
for (int i=1;i<=n;i++) print(ans[i]),putchar('\n');
return 0;
}