【洛谷1198 JSOI】最大數 單點更新線段樹+區間查詢最大值


題目描述

現在請求你維護一個數列,要求提供以下兩種操作:

1、 查詢操作。

語法:Q L

功能:查詢當前數列中末尾L個數中的最大的數,並輸出這個數的值。

限制:L不超過當前數列的長度。

2、 插入操作。

語法:A n

功能:將n加上t,其中t是最近一次查詢操作的答案(如果還未執行過查詢操作,則t=0),並將所得結果對一個固定的常數D取模,將所得答案插入到數列的末尾。

限制:n是整數(可能為負數)並且在長整范圍內。

注意:初始時數列是空的,沒有一個數。

輸入輸出格式

輸入格式:
第一行兩個整數,M和D,其中M表示操作的個數(M <= 200,000),D如上文中所述,滿足(0 < D<2,000,000,000)

接下來的M行,每行一個字符串,描述一個具體的操作。語法如上文所述。

輸出格式:
對於每一個查詢操作,你應該按照順序依次輸出結果,每個結果占一行。

輸入輸出樣例

輸入樣例#1:
5 100
A 96
Q 1
A 97
Q 1
Q 2
輸出樣例#1:
96
93
96

題解:線段樹裸題,因為最多有m次操作,那么首先建立一個m大小的線段樹,每個節點存儲最大值,初始值為極小值。每做一次A操作,就往線段樹中插入元素。Q操作要查詢區間最大值,同時要記錄這次查詢的元素,用作下一次A操作。

代碼:

/*Do not delay anything that adds laughter and joy to your life.*/
#include<iostream>
#include<cstdio>
#define N 2147283647
using namespace std;
struct node
{
int val;
int l,r;
}tree[3000005];
int m,d,num,t;
void build(int root,int l,int r) //建樹
{
int mid;
tree[root].l=l;tree[root].r=r;
if (l==r) tree[root].val=-N;
else
{
mid=(l+r)/2;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
tree[root].val=max(tree[root*2].val,tree[root*2+1].val);
}
}
void add(int root,int id,int addval) //單點更新
{
int mid;
if (tree[root].l==tree[root].r)
{
tree[root].val=addval;
return;
}
else
{
mid=(tree[root].l+tree[root].r)/2;
if (id<=mid) add(root*2,id,addval);
else add(root*2+1,id,addval);
tree[root].val=max(tree[root*2].val,tree[root*2+1].val);
}
}
int ask(int root,int l,int r)
{
int mid;
if (tree[root].l>=l&&tree[root].r<=r)
return tree[root].val;
else
{
mid=(tree[root].l+tree[root].r)/2;
if (mid>=r)
return ask(root*2,l,r);
else if (mid<l)
return ask(root*2+1,l,r);
else return max(ask(root*2,l,mid),ask(root*2+1,mid+1,r));

}
}
int main()
{
char c;
int i,x,tmp;
scanf("%d%d",&m,&d);
build(1,1,m);
for (i=1;i<=m;i++)
{
cin>>c;
scanf("%d",&x);
if (c=='A')
{
num++;
tmp=(x+t)%d;
add(1,num,tmp);
}
else
{
t=ask(1,num-x+1,num)%d;
printf("%d\n",t);
}
}
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com