大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)
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
A 96
Q 1
A 97
Q 1
Q 2
Sample Output
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)的更多相关文章
- bzoj-1012 1012: [JSOI2008]最大数maxnumber(线段树)
题目链接: 1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MB Description 现在请求你维护一个数列,要 ...
- bzoj 1012: [JSOI2008]最大数maxnumber (线段树)
1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 13081 Solved: 5654[Subm ...
- BZOJ 1012: [JSOI2008]最大数maxnumber 线段树
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1012 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作.语法:Q L 功能: ...
- 1012: [JSOI2008]最大数maxnumber 线段树
https://www.lydsy.com/JudgeOnline/problem.php?id=1012 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数 ...
- BZOJ 1012: [JSOI2008]最大数maxnumber【线段树单点更新求最值,单调队列,多解】
1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 10374 Solved: 4535[Subm ...
- BZOJ 1012: [JSOI2008]最大数maxnumber 单调队列/线段树/树状数组/乱搞
1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 4750 Solved: 2145[Submi ...
- BZOJ-1012[JSOI2008]最大数maxnumber 线段树区间最值
这道题相对简单下面是题目: 1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MB Submit: 6542 Solve ...
- BZOJ1012: [JSOI2008]最大数maxnumber [线段树 | 单调栈+二分]
1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 8748 Solved: 3835[Submi ...
- 【BZOJ】1012: [JSOI2008]最大数maxnumber(树状数组+rmq)
http://www.lydsy.com/JudgeOnline/problem.php?id=1012 树状数组原来我只懂得sum和add的操作,今天才知道可以有求区间最值的操作,我学习了一下写了个 ...
随机推荐
- MariaDB数据库主从复制实现步骤
一.MariaDB简介 MariaDB数据库的主从复制方案,是其自带的功能,并且主从复制并不是复制磁盘上的数据库文件,而是通过binlog日志复制到需要同步的从服务器上. MariaDB数据库支持单向 ...
- 中文Ubuntu里用户目录里的路径改成英文
(附注:转载于http://www.linuxdiyf.com/linux/201105/56.html) 为了使用起来方便,装了Ubuntu中文版,自然在home文件里用户目录的"桌面&q ...
- java限流(一): Semaphore
Before obtaining an item each thread must acquire a permit from the semaphore, guaranteeing that an ...
- HDFS权限
1.1 超级用户 启动namenode服务的用户就是超级用户, 该用户的组是supergroup 1.2 文件权限管理 1.2.1 创建时的owner和group 文件或者目录被创建之时,服从BS ...
- (4.14)存储:RAID在数据库存储上的应用
关键词:(4.14)存储:RAID在数据库存储上的应用 转自:http://blog.51cto.com/qianzhang/1251260 随着单块磁盘在数据安全.性能.容量上呈现出的局限,磁盘阵列 ...
- Python2 socket 多线程并发 TCPServer Demo
#coding=utf-8 import socket import threading,getopt,sys,string opts, args = getopt.getopt(sys.argv[1 ...
- 2015.7.8(千股跌停!做T不应当只做中色,中国软件)
2015.7.81.今天开盘所有的股票全部跌停,真是一大奇观! 今天中色股份和以往不同买卖盘为正! 但是中色的爬升比较慢,价位始终没有高过昨天的收盘价————这种情况下是否应该做T呢? 2.做T不应当 ...
- SqlHelper简单实现(通过Expression和反射)3.实体,数据传输对象(DTO)Helper类设计
EntityHelper的主要功能有: 1.通过反射获取DTO的字段,主要提供给在需要从Entity获取数据后,填充给DTO并返回的作用: 通过反射获取PropertyInfo[]对象,然后取出Nam ...
- Linux Shell基础 Bash常见命令 echo命令
概述 shell中常见的命令echo. 输出命令:echo echo命令的输出内容如果没有特殊含义,则将原内容输出到屏幕:如果输出内容有特殊含义,则输出打印其含义. 命令格式如下: [root@loc ...
- 【Tech】CAS RESTful API使用笔记
在被maven,cas,tomcat各种贱人就是矫情的虐了好几天之后,终于跑通了demo,哈哈哈哈哈哈哈~ 在这里详细记录一下,给和我一样连maven都不会的小白一点福利,同时欢迎大神指正. 首先上最 ...