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

[省选] [线段树] [BZOJ1012] JSOI2008 最大值 (max)

2016-04-26 19:07 585 查看
Description 题目描述

给定一列正整数al,a2,… ,an,每一个数都在0至p-1之间。可以对这列数进行两种操作:

添加操作:向序列后添加一个数,序列长度变成n+1。

询问操作:询问这个序列中最后L个数中最大的数是多少.

程序运行的最开始,整个序列为空。写一个程序,读入操作的序列,并输出询问操作的答案.

Input 输入

输入文件的第一行有两个正整数m(1≤m≤2*10^5)和p(1≤p≤2*10^9)。

接下来的m行,每行表示一个操作。

如果该行的内容是Q L,则表示这个操作是询问序列中最后L个数的最大数是多少;

如果是A t(0≤t≤p),则表示向序列后面加一个数,加入的数是:(t+a)除以p的余数。

其中,t是输入的参数,a是在这个添加操作之前最后一个询问操作的答案(如果之前没有询问操作,则a=0)。

第一个操作—定是添加操作。对于询问操作,L>0且不超过当前序列的长度。

Output 输出

对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数

Sample Input 样例输入

10 100

A 97

Q 1

Q 1

A 17

Q 2

A 63

Q 1

Q 1

Q 3

A 99

Sample Output 样例输出

97

97

97

60

60

97

很明显,这道题是裸线段树,先建一棵空树,开一个计数器记下已经进入的个数,两个操作就可以抽象为:

(1)加入操作(eg:加入R) 改一下num位置的值为(R+last)%p

(2)查询操作(eg:查最后R个) 查一下[num-R+1,num)的最大值即可

其实是水题,并没有怎么卡(想要卡的?看看2015山东省选第二轮D1 音质检测……)

上代码……

#include <cstdio>
#define MAXN 800000//开的好像有点大,不过也没事了^_^
using namespace std;

struct rec
{
int p,r,m;
int left,right;
int sum;
};

int m,p,top=1;
int num,last;//num为计数器,last为“上一次操作”的最后一个数
rec tree[2*MAXN]={};
char flag[3];
int n;

int mymax(int a,int b)
{
return a>b?a:b;
}
//以下为正常的线段树代码......
//代码区间为左闭右开,注意,注意
void Build_A_Tree(int u)
{
if (tree[u].p+1==tree[u].r) return;
tree[u].m=(tree[u].p+tree[u].r)/2;
top++;
tree[u].left=top;
tree[top].p=tree[u].p;
tree[top].r=tree[u].m;
Build_A_Tree(top);
top++;
tree[u].right=top;
tree[top].p=tree[u].m;
tree[top].r=tree[u].r;
Build_A_Tree(top);
}
//在看之前,请默念左闭右开
void modify (int u,int x,int v)
{
if ((tree[u].p+1==tree[u].r))
{
tree[u].sum=v;
return;
}
if (x<tree[u].m) modify(tree[u].left,x,v);
else modify(tree[u].right,x,v);
tree[u].sum=mymax(tree[tree[u].left].sum,tree[tree[u].right].sum);
}
//左闭右开
int query (int u,int a,int b)
{
if ((tree[u].p==a)&&(tree[u].r==b))
return tree[u].sum;
if (tree[u].m>=b) return query(tree[u].left,a,b);
else if (tree[u].m<=a) return query(tree[u].right,a,b);
else return mymax(query(tree[u].left,a,tree[u].m),query(tree[u].right,tree[u].m,b));
}

int main()
{
//freopen("data.in","r",stdin);freopen("data.out","w",stdout);
scanf("%d %d",&m,&p);
tree[1].p=1;
tree[1].r=m+1;//显然树的最大容量为m
Build_A_Tree(1);
while (m--)
{
scanf("%s",flag);//我讨厌输入字符......
scanf("%d",&n);
if (flag[0]=='A')//这里是加入操作
{
num++;
n=(n+last)%p;//按题目要求写
modify(1,num,n);
}
else//这里是查询操作
{
last=query(1,num-n+1,num+1);
printf("%d\n",last);
}
}
return 0;
}


线段树真是好东西……

数据可以在这里下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: