最大数 洛谷1198 JSOI2008

题意:

现在请求你维护一个数列,要求提供以下两种操作:

1、 查询操作。

语法:Q L

功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。

限制:L不超过当前数列的长度。(L>=0)

2、 插入操作。

语法:A n

功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。

限制:n是整数(可能为负数)并且在长整范围内。

注意:初始时数列是空的,没有一个数。

本题可以用线段树做(在洛谷上能过,但是我的代码在bzoj会T),似乎还可以单调队列甚至分块。我目前写的线段树都是传统的写法,不是zkw线段树。查询就是区间求区间[n-l+1,n]的最大值。记录一下上一个插入操作的返回值,然后插入相当于单点修改。那么考虑一下建树,发现在一开始我们不知道每个点的权值,所以我们只需要建一棵空树,建空树的目的是确定每个节点的左右子节点的编号。本题有一个小细节:当一开始数列里没有数的时候也会询问你最大数值,这时候要特判一下,输出0

下面发一下在洛谷AC的代码:(此代码直接交到bzoj会RE,原因尚不清楚)

#include <bits/stdc++.h>
using namespace std;

int m,d;
char s;
int ji,cnt;
struct node
{
	int r,l;
	int maxn,add;
}tr[4000050];
void build(int rt,int l,int r)
{
	tr[rt].l=l,tr[rt].r=r;
	if(l==r)
	{
		return;
	}
	int mid=(l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	return;
}
void pushdown(int rt)
{
	if(tr[rt].add)
	{
		tr[rt<<1].add+=tr[rt].add;
		tr[rt<<1|1].add+=tr[rt].add;
		tr[rt<<1].maxn+=tr[rt].add;
		tr[rt<<1|1].maxn+=tr[rt].add;
		tr[rt].add=0;
	}
	return;
}
void update(int rt,int le,int ri,long long x)
{
	int l=tr[rt].l,r=tr[rt].r;
	if(le<=l&&r<=ri)
	{
		tr[rt].maxn=tr[rt].maxn+x;
		tr[rt].add+=x;
		return;
	}
	pushdown(rt);
	int mid=(l+r)>>1;
	if(le<=mid)
	update(rt<<1,le,ri,x);
	if(ri>mid)
	update(rt<<1|1,le,ri,x);
	tr[rt].maxn=max(tr[rt<<1].maxn,tr[rt<<1|1].maxn);
	return;
}
int query(int rt,int le,int ri)
{
	int l=tr[rt].l,r=tr[rt].r;
	if(le<=l&&ri>=r)
	return tr[rt].maxn;
	pushdown(rt);
	int res=-2147483647;
	int mid=(l+r)>>1;
	if(le<=mid)
	res=query(rt<<1,le,ri);
	if(ri>mid)
	res=max(res,query(rt<<1|1,le,ri));
	if(res==-2147483647)//特判l=0
	return 0; 
	return res;
}

int main()
{
	scanf("%d%d",&m,&d);
	build(1,1,200000);
	for(int i=1;i<=m;i++)
	{
		long long x;
		cin>>s>>x;
		if(s=='Q')
		{
			ji=query(1,cnt-x+1,cnt);
			printf("%d\n",ji);
		}
		if(s=='A')
		{
			cnt++;
			update(1,cnt,cnt,(x+ji)%d);
		}
	}
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值