您的位置:首页 > Web前端 > JavaScript

[JSOI2008]最大数 线段树解法

2017-03-07 21:19 351 查看

题目描述

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

1、 查询操作。

语法:Q L

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

限制:L不超过当前数列的长度。

2、 插入操作。

语法:A n

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

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

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

                                  --by luogu
https://daniu.luogu.org/problem/show?pid=1198
先把序列的空位建好线段树,初始序列是空的,就先建为极小值(注意她是负的),对每个A操作,就是在相应位置单点修改,对每个Q操作,就是查询相应的位置的区间最值

位置是什么呢?

发现只要记下当前序列的结尾就迎刃而解啦;

代码如下:

#include<cstdio>
using namespace std;
long long D,n,t;
int tree[1000000];
int m,len;
void build(int ,int ,int );
void change(int ,int, int ,int );
int MAX(int ,int ,int ,int ,int );
int main()
{
int i,j,k,l;
char c;
scanf("%d%d",&m,&D);
build(1,m,1);
for(i=1;i<=m;i++){
c=getchar();
while(c!='A'&&c!='Q')
c=getchar();
if(c=='A'){
scanf("%lld",&n);
n=(n+t)%D;
change(1,m,1,len+1);
len++;
}
if(c=='Q'){
scanf("%d",&l);
t=MAX(1,m,1,len-l+1,len);
printf("%lld\n",t);
}
}
return 0;
}
void build(int l,int r,int nu){
if(l==r){
tree[nu]=-2147483600;
return;
}
int mid=(l+r)>>1;
build(l,mid,nu<<1);build(mid+1,r,nu<<1|1);
tree[nu]=-2147483600;
}
void change(int l,int r,int nu,int x){
if(l==r){
tree[nu]=n;
return ;
}
int mid=(l+r)>>1;
if(x<=mid)
change(l,mid,nu<<1,x);
else
change(mid+1,r,nu<<1|1,x);
if(tree[nu<<1]>tree[nu<<1|1])
tree[nu]=tree[nu<<1];
else
tree[nu]=tree[nu<<1|1];
}
int MAX(int l,int r,int nu,int L,int R){
if(L<=l&&r<=R)
return tree[nu];
int mid=(l+r)>>1;
int Lmax=-2147483600,Rmax=-2147483600;
if(L<=mid)
Lmax=MAX(l,mid,nu<<1,L,R);
if(R>=mid+1)
Rmax=MAX(mid+1,r,nu<<1|1,L,R);
if(Lmax>Rmax)
return Lmax;
return Rmax;
}


话说代码真难看呵;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: