[JSOI2008]最大数(线段树基础)

题目描述

现在请求你维护一个数列,要求提供以下两种操作:

1、 查询操作。

语法:Q L

功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。

限制: L 不超过当前数列的长度。(L > 0)

2、 插入操作。

语法:A n

功能:将 n 加上 t ,其中 t 是最近一次查询操作的答案(如果还未执行过查询操作,则 t=0 ),并将所得结果对一个固定的常数 D  取模,将所得答案插入到数列的末尾。

限制: n 是整数(可能为负数)并且在长整范围内。

注意:初始时数列是空的,没有一个数。

输入输出格式

输入格式:

第一行两个整数, M 和 D ,其中 M 表示操作的个数 (M≤200,000), D 如上文中所述,满足 (0<D<2,000,000,000)

接下来的 M 行,每行一个字符串,描述一个具体的操作。语法如上文所述。

输出格式:

对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。

思路:

从这道题的数据范围来看,他只有200000次操作

从最坏情况来看,数列长最多只可能200000

所以,这道题就变成了一道简单的线段树

我们默认这是一棵已经开好的大小为200000的线段树

A操作就是单点修改

Q操作就是区间查询

每个节点维护的是当前节点及其子树的最大值

A操作就是一个简单的单点修改,只要记录上一次修改的位置,+1就是要修改的位置

Q操作就是一个区间查询,查询该区间的最大值,只要改变return的东西就好了

代码:

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#define rii register int i
using namespace std;
struct node{
    long long maxn;
}x[800005];
char cz;
long long v,ans,m,d,mw;
long long add(int wz,long long val,int l,int r,int bh)
{
    if(l==r)
    {
        x[bh].maxn+=val;
        return x[bh].maxn;
    }
    int harf=(l+r)/2;
    if(wz>harf)
    {
        x[bh].maxn=max(x[bh].maxn,add(wz,val,harf+1,r,bh*2+1));
    }
    else
    {
        x[bh].maxn=max(x[bh].maxn,add(wz,val,l,harf,bh*2));
    }
    return x[bh].maxn;
}
long long ask(int l,int r,int nl,int nr,int bh)
{
    long long ltt=0;
    if(l==nl&&r==nr)
    {
        return x[bh].maxn;
    }
    int half=(nl+nr)/2;
    if(l<=half&&r>half)
    {
        ltt=max(ltt,ask(l,half,nl,half,bh*2));
        ltt=max(ltt,ask(half+1,r,half+1,nr,bh*2+1));
    }
    else
    {
        if(l<=half)
        {
            ltt=max(ltt,ask(l,r,nl,half,bh*2));
        }
        else
        {
            ltt=max(ltt,ask(l,r,half+1,nr,bh*2+1));
        }
    }
    return ltt;
}
int main()
{
    scanf("%lld%lld\n",&m,&d);
    for(rii=1;i<=m;i++)
    {
        scanf("%c%lld\n",&cz,&v);
        if(cz==‘Q‘)
        {
            ans=ask(mw-v+1,mw,1,200000,1);
            printf("%d\n",ans);
        }
        else
        {
            mw++;
//            ans=1e9+7;
//            r1=max(r1,v);
            add(mw,(ans+v)%d,1,200000,1);
//            cout<<x[1].maxn;
        }
    }
}

原文地址:https://www.cnblogs.com/ztz11/p/9296499.html

时间: 2024-10-16 09:14:26

[JSOI2008]最大数(线段树基础)的相关文章

[JSOI2008]最大数 --线段树

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

P1198 [JSOI2008]最大数 线段树

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

线段树 基础单点更新 敌兵布阵

题:敌兵布阵 标准线段树模板代码: #include<cstdio> #include<cstring> const int maxn = 500000 + 10; struct Node{ int left, right, count; }node[maxn]; int a[maxn]; /*********************************** ***************建树**************** ************i是区间序号********

线段树基础知识----(基础数据结构)--(一)

1.定义 引入:为什么要使用线段树而不用数组模拟呢? answer:因为有些题用数组来做就要超时,用线段树的O(log(n))的时间复杂度刚好可以求解 毫无疑问线段树是一种数据结构,但是它实际是一个类似树状的链表结构(个人认为) ///还是要正经一点(照搬教科书)----------- / ////////////////////////////////////////////////////////////////////// 线段树定义:线段树是一种二叉搜索树,与区间树相似,它将一个区间划分

线段树基础

关于线段树的原理学习,可以参看杨弋大牛的论文<线段树>以及刘汝佳老师的<算法竞赛入门经典(训练指南)>,代码风格学习hzwer或者notonlysuccess均可. 一.单点更新 最基础的线段树 题目:codevs1080 链接:http://codevs.cn/problem/1080/ 分析:最简单的线段树,单点更新,区间求和 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4

最大最小值(线段树基础版)

最大最小值 时间限制:1000 ms  |  内存限制:65535 KB 描述 给出N个整数,执行M次询问. 对于每次询问,首先输入三个整数C.L.R: 如果C等于1,输出第L个数到第R个数之间的最小值: 如果C等于2,输出第L个数到第R个数之间的最大值: 如果C等于3,输出第L个数到第R个数之间的最小值与最大值的和. (包括第L个数和第R个数). 输入 首先输入一个整数T(T≤100),表示有T组数据. 对于每组数据,先输入一个整数N(1≤N≤10000),表示有N个整数: 接下来一行有N个整

HDU 1754--I Hate It(线段树基础)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 44820    Accepted Submission(s): 17591 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的

【线段树基础】NKOJ 1321 数列操作

时间限制 : 10000 MS   空间限制 : 165536 KB 问题描述 假设有一列数{Ai}(1≤i≤n),支持如下两种操作:将Ak的值加D.(k, D是输入的数)输出As+As+1+…+At.(s, t都是输入的数,S≤T) 输入格式 第一行一个整数n,第二行为n个整数,表示{Ai}的初始值≤10000.第三行为一个整数m,表示操作数下接m行,每行描述一个操作,有如下两种情况:ADD k d (表示将Ak加d,1<=k<=n,d为数,d的绝对值不超过10000)SUM s t (表示

POJ2528线段树基础

开始就直接用延迟标记搞了下,最后发现内存肯定会爆了,数据太大了: 问了瓜神,原来应该用离散化来做这题,具体见注释 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #in