Rabbit的数列 (懒人+区间最大值最小值)

链接:https://ac.nowcoder.com/acm/contest/328/D
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

Rabbit得到了一个长度为N的数列(数列编号从0到N−1)。数列中每个数vali满足1<=vali<=C。
初始时数列中每个数均为1,现在Rabbit要对这个数列进行Q次操作,每次操作给出四个数:X Y A B,首先查询数列中值为X的个数P,然后计算出L,R:
L=(A+(P+B)2)mod N
R=(A+(P∗B)2)mod N
并将范围[min(L,R),max(L,R)]内的所有数改为Y。
最后询问经过Q次操作后数列中出现次数最多的那个数出现了几次。 
 

输入描述:

第一行三个整数N,C,Q。

接下来Q行,每行四个整数X,Y,A,B,表示一个操作。

输出描述:

输出一个整数,表示经过Q次操作后数列中出现次数最多的那个数出现的次数。

示例1

输入

复制

4 2 1
2 2 1 1

输出

复制

2

备注:

 

1<=N,C,Q<=105

1<=X,Y<=C,1<=A,B<=108

A,B通过随机产生

这题是看别人的博客补的,我感觉就是利用懒人标记节约更新的时间,然后利用线段树的最大值和最小值查找区间。

 

刚开始我用最初的结构体去写这题,发现超时了(第一篇代码),因为每次建树的时候会浪费时间,而且建树的时候没有其他操作了,痛定思痛,决定以后换一种模板,在看了许老师的模板,模仿再加以修饰,我终于AC了(第二篇代码)。

 

这个第二篇的好处呢就是不需要建树,节约很多时间,但是有一个小小的坏处,就是不能根据编号id查询他本身的区间l,r,例如调用pushdown的时候,只能将l,r传过去。

 

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
int vis[maxn],ans;
struct node
{
	int tag,mx,mn,l,r;
}tr[maxn*4];
void build(int id,int l,int r)
{
	tr[id].l=l,tr[id].r=r;
	if (id!=1)tr[id].tag=0;
	if(l==r) return ;
	int mid=(l+r)>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
}
void pushdown(int id)
{
	if(tr[id].tag)
	{
		tr[id].mx=tr[id].mn=tr[id].tag;
		if(tr[id].l!=tr[id].r)
		{
			tr[id<<1].tag=tr[id<<1|1].tag=tr[id].tag;
			tr[id<<1].mx=tr[id<<1|1].mx=tr[id].tag;
			tr[id<<1].mn=tr[id<<1|1].mn=tr[id].tag;
		}
		tr[id].tag=0;
	}
}
void update(int id,int l,int r,int v)
{
	pushdown(id);
	if(l<=tr[id].l&&tr[id].r<=r&&tr[id].mx==tr[id].mn)
	{
		vis[tr[id].mx]-=(r-l+1);
		vis[v]+=(r-l+1);
		tr[id].tag=v;
		pushdown(id);
		return ;
	}
	int mid=tr[id].l+tr[id].r>>1;
	if(l<=mid) update(id<<1,l,r,v);
	if(r>mid) update(id<<1|1,l,r,v);
	tr[id].mx=max(tr[id<<1].mx,tr[id<<1|1].mx);
	tr[id].mn=min(tr[id<<1].mn,tr[id<<1|1].mn);
}
int main()
{
	int n,c,q,x,y;
	ll a,b;
	scanf("%d%d%d",&n,&c,&q);
	vis[1]=n;
	tr[1].tag=1;
	build(1,1,n);
	while(q--)
	{
		scanf("%d%d%lld%lld",&x,&y,&a,&b);
		int p=vis[x];
		int l=(a+(p+b)%n*(p+b)%n)%n+1;
		int r=(a+p*b%n*p%n*b%n)%n+1;
		if(l>r) swap(l,r);
		update(1,l,r,y);
	}
	for(int i=1;i<=c;i++)
	ans=max(ans,vis[i]);
	printf("%d\n",ans);
}
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
int vis[maxn];
int lazy[maxn*4],mx[maxn*4],mn[maxn*4];

void pushdown(int id,int l,int r)
{
	if(lazy[id])
	{
		mx[id]=mn[id]=lazy[id];
		if(l!=r)
		{
			lazy[id<<1|1]=lazy[id<<1]=lazy[id];
			mx[id<<1]=mx[id<<1|1]=lazy[id];
			mn[id<<1]=mn[id<<1|1]=lazy[id];
		}
		lazy[id]=0;
	}
}
void update(int id,int l,int r,int ql,int qr,int v)
{
	pushdown(id,l,r);
	if(ql<=l&&r<=qr&&mx[id]==mn[id])
	{
		vis[mx[id]]-=(r-l+1);
		vis[v]+=(r-l+1);
		lazy[id]=v;
		pushdown(id,l,r);
		return ;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) update(id<<1,l,mid,ql,qr,v);
	if(qr>mid) update(id<<1|1,mid+1,r,ql,qr,v);
	mx[id]=max(mx[id<<1],mx[id<<1|1]);
	mn[id]=min(mn[id<<1],mn[id<<1|1]);
}
int main()
{
	int n,c,q,x,y;
	ll a,b;
	scanf("%d%d%d",&n,&c,&q);
	vis[1]=n;
	lazy[1]=1;
	while(q--)
	{
		scanf("%d%d%lld%lld",&x,&y,&a,&b);
		int p=vis[x];
		int l=(a+(p+b)%n*(p+b)%n)%n+1;
		int r=(a+p*b%n*p%n*b%n)%n+1;
		if(l>r) swap(l,r);
		update(1,1,n,l,r,y);
	}
	int ans=0;
	for(int i=1;i<=c;i++)
	ans=max(ans,vis[i]);
	printf("%d\n",ans);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ccsu_deer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值