1012: [JSOI2008]最大数maxnumber

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 9851  Solved: 4318
[Submit][Status][Discuss]

Description

  现在请求你维护一个数列,要求提供以下两种操作:1、 查询操作。语法:Q L 功能:查询当前数列中末尾L
个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。2、 插入操作。语法:A n 功能:将n加
上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取
模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个
数。

Input

  第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足D在longint内。接下来
M行,查询操作或者插入操作。

Output

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

Sample Input

5 100
A 96
Q 1
A 97
Q 1
Q 2

Sample Output

96
93
96

HINT

  数据如下http://pan.baidu.com/s/1i4JxCH3

Source

线段树

 #include <bits/stdc++.h>
using namespace std; #define L(root) ((root) << 1)
#define R(root) (((root) << 1) | 1) const int MAXN = + ;
int numbers[MAXN]; struct Node {
int left, right;
//int sum;//
int mx;//最大值
int mid()
{
return left + ((right - left) >> );
}
} tree[MAXN * ]; void pushUp(int root)
{
// tree[root].sum = tree[L(root)].sum + tree[R(root)].sum;
tree[root].mx = max(tree[L(root)].mx, tree[R(root)].mx);
} void build(int root, int left, int right)
{
tree[root].left = left;
tree[root].right = right;
if (left == right) {
// tree[root].sum = numbers[left];
tree[root].mx = ;
return;
}
int mid = tree[root].mid();
build(L(root), left, mid);
build(R(root), mid + , right);
pushUp(root);
} int query(int root, int left, int right)
{
if (tree[root].left == left && tree[root].right == right) {
// return tree[root].sum;
return tree[root].mx;
}
int mid = tree[root].mid();
if (right <= mid) {
return query(L(root), left, right);
} else if (left > mid) {
return query(R(root), left, right);
} else {
//return query(L(root), left, mid) + query(R(root), mid + 1, right);
//注意返回最大值...
int lv = query(L(root), left, mid);
int rv = query(R(root), mid + , right);
return lv > rv ? lv : rv;
}
} void update(int root, int pos, int add)
{
if (tree[root].left == tree[root].right) {
//tree[root].sum = tree[root].sum + add;
tree[root].mx = add;
return;
}
int mid = tree[root].mid();
if (pos <= mid) {
update(L(root), pos, add);
} else {
update(R(root), pos, add);
}
pushUp(root);
} void test01()
{
memset(numbers, , sizeof(numbers));
int i;
for (i = ; i < MAXN; ++i) {
numbers[i] = i;
}
build(, , );
printf("%d\n", query(, , ));
update(, , );
printf("%d\n", query(, , ));
} int main()
{
//test01(); int M, D;
char str[];
int x;
int i;
int t;
int len;//当前长度 while (~scanf("%d%d", &M, &D)) {
build(, , M); t = ;
len = ;
for (i = ; i < M; ++i) {
scanf("%1s%d", str, &x);
if (str[] == 'Q') {
t = query(, len - x + , len);
printf("%d\n", t);
} else {
update(, ++len, (x + t) % D);
}
}
} return ;
}

树状数组(代码好难理解,日后再看)

区间最值其实和区间求和差不多,就是将sum数组的含义转移到max,然后通过特定的区间更新max。

在区间求和中,当我们维护max[i]的时候,要找到它前面所有的max[j]来更新,在这里因为是树状数组,所以可以降成一个log级,画图可知,max[i]需要的max只有max[i-^],max[i-^],max[i-^]..max[i-lowbit(i)+]

更新操作简单,即

void change(int r) {
c[r]=num[r];
for(int i=; i<lowbit(r); i<<=)
c[r]=max(c[r], c[r-i]);
}
接下来是求区间最值,很容易看出,我们找[l,r]的最值就是找在次区间的max,即递减r,在这里可以有个优化,即当找到一个max[i],有i-lowbit(i)>=l时,更新后,i直接-=lowbit(i),然后继续递减。当l>=r就跳出循环 int getk(int l, int r) {
int ret=num[r];
while(l<=r) {
ret=max(ret, num[r]);
for(--r; r-l>=lowbit(r); r-=lowbit(r))
ret=max(ret, c[r]);
}
return ret;
}
其实在这里更新操作可以和区间最值放在一起,(现在用c代表max)即c[i]=max(getk(i-lowbit(i)+, i), num[i]);
 #include <cstdio>
using namespace std;
#define lowbit(x) (x&-x)
#define max(a,b) ((a)>(b)?(a):(b))
const int N=;
int num[N], c[N], cnt;
int getk(int l, int r) {
int ret=num[r];
while(l<=r) {
ret=max(ret, num[r]);
for(--r; r-l>=lowbit(r); r-=lowbit(r))
ret=max(ret, c[r]);
}
return ret;
} int main() {
int n, d, t=, a;
char ch[];
scanf("%d%d", &n, &d);
while(n--) {
scanf("%s%d", ch, &a);
if(ch[]=='A') {
num[++cnt]=(t+a)%d;
c[cnt]=max(getk(cnt-lowbit(cnt)+, cnt-), num[cnt]);
}
else {
printf("%d\n", t=getk(cnt-a+, cnt));
}
}
return ;
}

单调递减队列/ 单调递增栈

 #include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#define N 1000000
#define INF INT_MAX using namespace std; //单调递减队列, [队首, 队尾], [3, 2, 1], 队列中存下标
//单调递增栈, [栈底, 栈顶], [3, 2, 1]
int q[N],m,d,h=,t=,num;
int val[N],ans; //二分找到x后面第一个数
inline int getans(int x)
{
int l=h,r=t-,mid,res;
while(l<=r)
{
mid=(l+r)>>;
if(x<=q[mid]) res=mid,r=mid-;
else l=mid+;
}
return q[res];
} inline void go()
{
scanf("%d%d",&m,&d);
int a;
char str[];
while(m--)
{
scanf("%s%d",str,&a);
if(str[]=='A')
{
val[++num]=(a+ans)%d;
while(h<t&&val[q[t-]]<=val[num]) t--;
q[t++]=num;
}
else
{
//二分
ans=val[getans(num-a+)];
printf("%d\n",ans);
}
}
} int main()
{
go();
return ;
}

下面的代码比较挫了,如果输入序列递增,估计要超时。辅助理解单调队列思想。

 //qscqesze
#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <typeinfo>
#include <fstream>
#include <map>
typedef long long ll;
using namespace std;
//freopen("D.in","r",stdin);
//freopen("D.out","w",stdout);
#define sspeed ios_base::sync_with_stdio(0);cin.tie(0)
#define maxn 250001
#define eps 1e-9
const int inf=0x7fffffff; //无限大
//**************************************************************************************
int a[maxn],max_num[maxn],t=,ans=;
int main()
{
int n,d;
scanf("%d%d",&n,&d);
char ch[];
int g;
while(n--)
{
scanf("%s%d",ch,&g);
if(ch[]=='A')
{
a[++t]=(ans+g)%d;
for(int i=t;i;i--)
{
if(max_num[i]<a[t])
max_num[i]=a[t];
else
break;
}
}
else
{
ans=max_num[t-g+];
printf("%d\n",ans);
}
}
return ;
}

rmq(我写的这个速度有点捉急...)

 #include <bits/stdc++.h>
using namespace std; const int MAXN = + ;
int mx[MAXN][];
int num[MAXN];
int tot; void update()
{
mx[tot][] = num[tot];
int k1 = log2(tot);
int k2;
int i, j;
for (j = ; j <= k1; ++j) {
k2 = tot - pow(, j) + ;
for (i = k2; i <= k2; ++i) {
mx[i][j] = max(mx[i][j - ], mx[i + (int)pow(, j - )][j - ]);
}
}
} int rmq(int i, int j)
{
int k = log2(j - i + );
return max(mx[i][k], mx[j - (int)pow(, k) + ][k]);
} int main()
{
int M, D;
char str[];
int x;
int i;
int t; while (~scanf("%d%d", &M, &D)) {
tot = ;
t = ;
for (i = ; i < M; ++i) {
scanf("%1s%d", str, &x);
if (str[] == 'Q') {
t = rmq(tot - x + , tot);
printf("%d\n", t);
} else {
num[++tot] = (x + t) % D;
update();
}
}
} return ;
}

大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)的更多相关文章

  1. bzoj-1012 1012: [JSOI2008]最大数maxnumber(线段树)

    题目链接: 1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MB Description 现在请求你维护一个数列,要 ...

  2. bzoj 1012: [JSOI2008]最大数maxnumber (线段树)

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 13081  Solved: 5654[Subm ...

  3. BZOJ 1012: [JSOI2008]最大数maxnumber 线段树

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1012 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作.语法:Q L 功能: ...

  4. 1012: [JSOI2008]最大数maxnumber 线段树

    https://www.lydsy.com/JudgeOnline/problem.php?id=1012 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数 ...

  5. BZOJ 1012: [JSOI2008]最大数maxnumber【线段树单点更新求最值,单调队列,多解】

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 10374  Solved: 4535[Subm ...

  6. BZOJ 1012: [JSOI2008]最大数maxnumber 单调队列/线段树/树状数组/乱搞

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 4750  Solved: 2145[Submi ...

  7. BZOJ-1012[JSOI2008]最大数maxnumber 线段树区间最值

    这道题相对简单下面是题目: 1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MB Submit: 6542 Solve ...

  8. BZOJ1012: [JSOI2008]最大数maxnumber [线段树 | 单调栈+二分]

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 8748  Solved: 3835[Submi ...

  9. 【BZOJ】1012: [JSOI2008]最大数maxnumber(树状数组+rmq)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1012 树状数组原来我只懂得sum和add的操作,今天才知道可以有求区间最值的操作,我学习了一下写了个 ...

随机推荐

  1. 【题解】CF611H New Year and Forgotten Tree

    [题解]CF611H New Year and Forgotten Tree 神题了... 题目描述 给定你一棵树,可是每个节点上的编号看不清了,只能辨别它的长度.现在用问号的个数代表每个节点编号那个 ...

  2. [BZOJ3551]Peaks

    [BZOJ3551]Peaks BZOJ luogu 建Kruskal重构树,点权为边权 按dfn序建出主席树 倍增找到能跳到的最浅的祖先 主席树查询一下 #include<bits/stdc+ ...

  3. 斯坦福大学Andrew Ng - 机器学习笔记(7) -- 异常检测

    大概用了一个月,Andrew Ng老师的机器学习视频断断续续看完了,以下是个人学习笔记,入门级别,权当总结.笔记难免有遗漏和误解,欢迎讨论. 鸣谢:中国海洋大学黄海广博士提供课程视频和个人笔记,在此深 ...

  4. Java的变量命名

    Java的变量命名 1.首字母是英文字母.$和下划线,由字母.数字和下划线组成.  [很常规] 2.变量的命名遵循见名知义的原则.  [很重要,比如名字就用 name ,而不是用a.b.c这样的命名, ...

  5. 爬虫基础库之requests模块

    一.requests模块简介 使用requests可以模拟浏览器请求,比起之前用到的urllib,requests模块的api更加快捷,其实ruquests的本质就是封装urllib3这个模块. re ...

  6. active admin

    activeadmin 1.0.0.pre4 所依赖的库 gem 'jquery-rails', '~> 4.0.4' 4.2版本会出现找不到jquery-ui 的datepicker错误 使用 ...

  7. 算法寒假实习面试经过之 十一贝(offer) 联想研究院(电话一面 被拒)

    联想研究院 1面 自我介绍 聊比赛,讲了讲jdd的. 感觉都快要背过了... 之前重复的问题就不说了,说一下印象比较深的 adaboost 与gbdt的区别 随机森林,如果有t个特征,n个树,每个树深 ...

  8. 教你在Yii2.0框架中如何创建自定义小部件

    本教程将帮助您创建自己的自定义小部件在 yii framework 2.0.部件是可重用的模块和用于视图. 创建一个小部件,需要继承 yii\base\Widget,覆盖重写 yii\base\Wid ...

  9. Java泛型详解(转)

    文章转自  importNew:Java 泛型详解 引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用.本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理 ...

  10. mysql 触发器 存储过程 java调用

    触发器和存储过程是为了提高SQL的运行效率. SQL语句先编译.后执行,而触发器与存储过程都会提前预编译完成,且只编译一次,供反复调用. 随着时代的进步,硬件与带宽的提升,触发器和存储过程提升效率并不 ...