BZOJ1012 JSOI2008 最大数maxnumber 线段树/栈+二分法

题意:给定一个数列,要求维护:1、求倒数L个数中的最大值  2、在数列末尾插入(最近的1询问的答案+x)%D。其中初始序列为空。

法一:因为询问最多200000个,所以直接建一棵大小为M的线段树维护即可

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

struct Node{
    int l,r,m;
    Node *lchild,*rchild;

    Node(){}
    Node(int _l,int _r):l(_l),r(_r),m(0),lchild(0),rchild(0){}
}*Root;
int N,M,D,x,t;
char Order[6];

void Pushup(Node *&x){ x->m=max(x->lchild->m,x->rchild->m);}

void Build(Node *&x,int l,int r){
    x=new Node(l,r);
    if(l==r) return;

    int m=(l+r)>>1;
    Build(x->lchild,l,m),Build(x->rchild,m+1,r);
}

void Update(Node *&x,int p,int v){
    if(x->l==x->r){
        x->m=v;
        return;
    }

    int m=(x->l+x->r)>>1;
    if(p<=m) Update(x->lchild,p,v);
    else Update(x->rchild,p,v);
    Pushup(x);
}

int Query(Node *&x,int l,int r){
    if(l<=x->l && x->r<=r) return x->m;

    int m=(x->l+x->r)>>1,Ans=-1;
    if(l<=m) Ans=Query(x->lchild,l,r);
    if(m<r) Ans=max(Ans,Query(x->rchild,l,r));
    return Ans;
}

int main(){
    scanf("%d %d",&M,&D);

    Build(Root,1,M);
    for(int i=1,p;i<=M;i++){
        scanf("%s",Order);

        if(Order[0]==‘Q‘){
            cin >> p;
            cout << (t=Query(Root,N-p+1,N)) << endl;
        }
        else{
            cin >> x;
            N++,Update(Root,N,(x+t)%D);
        }
    }

    return 0;
}

法二:显然对于任意一个位置的数,其之前比它小的数在之后的询问中肯定没有贡献。所以维护一个单调栈,用二分来回答询问。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define ll long long

const int MAXN=200000+2;
int M,N,s[MAXN],C,D,t,a[MAXN];
char Order[6];

int main(){
    scanf("%d%d",&M,&D);
    while(M--){
        int x;
        scanf("%s%d",Order,&x);

        if(Order[0]==‘Q‘){
            int p=lower_bound(s+1,s+N+1,C-x+1)-s;
            printf("%d\n",t=a[s[p]]);
        }
        else{
            x=(x+t)%D,a[++C]=x;
            while(N && a[s[N]]<=x) N--;
            s[++N]=C;
        }
    }

    return 0;
}

时间: 2024-12-29 13:07:12

BZOJ1012 JSOI2008 最大数maxnumber 线段树/栈+二分法的相关文章

[BZOJ1012][JSOI2008]最大数maxnumber 线段树

没什么好说的--线段树维护区间就行了.第一次居然写错了,真丢人. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 ll inline readll(){ 7 ll Num;char ch; 8 while((ch=getchar())<'0'||ch>'9');Num=ch-'0'; 9

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

题目链接: 1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MB Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插入操作.语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得

BZOJ 1012: [JSOI2008]最大数maxnumber(线段树)

裸的线段树...因为数组开小了而一直RE..浪费了好多时间.. -------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cctype> #include<iostream> #define rep(i,n) for(int i=

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

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

【BZOJ】1012: [JSOI2008]最大数maxnumber(树状数组+区间最值)

http://www.lydsy.com/JudgeOnline/problem.php?id=1012 树状数组原来我只懂得sum和add的操作,今天才知道可以有求区间最值的操作,我学习了一下写了个,1a了. 区间最值其实和区间求和差不多,就是将sum数组的含义转移到max,然后通过特定的区间更新max. 在区间求和中,当我们维护max[i]的时候,要找到它前面所有的max[j]来更新,在这里因为是树状数组,所以可以降成一个log级,画图可知,max[i]需要的max只有max[i-2^0],

单调栈 BZOJ1012 [JSOI2008]最大数maxnumber

1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 10440  Solved: 4571[Submit][Status][Discuss] Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L 个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插入操作.语法:A n 功能:将n加 上t,其中t是最近一

【听说是线段树】bzoj1012 [JSOI2008]最大数maxnumber

一眼看题目吓了一跳:这TM不就是单调队列吗,200000又怎样,大不了我二分嘛 系统提示:成功开启 手残模式 开始瞎写: 1 #include <cstdio> 2 long long a[200001]; 3 int b[200001]; 4 int m,mod; 5 int find(int l,int r,long long x) 6 { 7 if(l>=r-1) 8 if(a[r]>=x) 9 return r; 10 else 11 return l; 12 int mi

[BZOJ1012] [JSOI2008] 最大数maxnumber (ST表)

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

bzoj1012 [JSOI2008]最大数maxnumber

这道题有很多的做法 裸的线段树 #include<cstdio> #define lc o*2 #define rc o*2+1 #define mid (l+r)/2 inline int max(int x,int y){ return x>y? x:y; } inline int read(){ char c; while(c=getchar(),c<'0' || c>'9'); int x=c-'0'; while(c=getchar(),c>='0' &