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. 洛谷 P4171 [JSOI]满汉全席

    洛谷 最近刚刚学的2-sat,就刷了这道裸题. 2-sat问题一般是用tarjan求的,当出现(x,y)或(!x,y)或(x,!y)三种选择时,我们可以把!x->y,!y->x连边. 然后 ...

  2. 安装CentOS 7.4 可能会出现的坑以及解决方案

    安装CentOS 7.4 可能会出现的坑以及解决方案 (解决方法不唯一,如果行不通的话emmmm~~, 百度会啥你会啥~~) 坑.0X01 解决: 退出虚拟机,以管理员权限运行 坑.0X02 解决: ...

  3. Python 中星号作用:解包&打散

    python中’*’和’**’的使用分两个方面,一个是计算,另一个是参数传递过程中元素的打包和解包.  计算方面 ‘*’和’**’在python中最常见的作用分别是‘相乘’和‘乘幂’,如下: > ...

  4. 我的Android进阶之旅------>Android项目运行报java.lang.NoClassDefFoundError错误的解决办法

    今天在运行一个Android项目的时候,报了以下错误: D/AndroidRuntime( 3859): Shutting down VM E/AndroidRuntime( 3859): FATAL ...

  5. tomcat8.5.11的manager页面总是提示403的问题

    修改conf/tomcat-users.xml加入: <role rolename="manager"/> <role rolename="manage ...

  6. django用户信息扩展

    Django封装了好多东西,拿来用就可以了,帮我们封装类用户的登录认证,用户的表 所以Django自带有用户表,当扩展用户表后一些表就会被替换 用户认证相关的    功能放在django.contri ...

  7. 2015.7.2 想做T再次失败

    2015.7.2教训:不要心存侥幸! 1.昨天收盘急跌,加上看到成交量在增加,负荷庄家行为第五条,一时脑热就去抄了.其实在震荡行情下,第二天肯定有时间点比头一天的收盘价低(Pic1) 2.T+0原则: ...

  8. Bootstrap入门教程

    资料来源: http://www.cnblogs.com/ventlam/archive/2012/05/28/2520703.html 1.全局样式:Bootstrap要求html5的文件类型,所以 ...

  9. Oracle索引(1)概述与创建索引

    索引是为了提高数据检索效率而创建的一种独立于表的存储结构,由Oracle系统自动进行维护. 索引的概述        索引是一种可选的与表或簇相关的数据库对象,能够为数据的查询提供快捷的存储路径,减少 ...

  10. OS路径模块命令

    os.remove():删除指定文件os.rmdir():删除指定目录os.mkdir():创建单级目录os.makedirs():创建多级目录os.listdir(dirname):列出dirnam ...