AcWing. 1275 最大数 (单点修改 + 区间查询)

简介: 笔记

AcWing. 1275最大数


给定一个正整数数列 a1,a2,…,an,每一个数都在 0∼p−1 之间。


可以对这列数进行两种操作:


添加操作:向序列后添加一个数,序列长度变成 n+1;

询问操作:询问这个序列中最后 L 个数中最大的数是多少。

程序运行的最开始,整数序列为空。


写一个程序,读入操作的序列,并输出询问操作的答案。


输入格式

第一行有两个正整数 m,p,意义如题目描述;


接下来 m 行,每一行表示一个操作。


如果该行的内容是 Q L,则表示这个操作是询问序列中最后 L 个数的最大数是多少;


如果是 A t,则表示向序列后面加一个数,加入的数是 (t+a) mod p。其中,t 是输入的参数,a 是在这个添加操作之前最后一个询问操作的答案(如果之前没有询问操作,则 a=0)。


第一个操作一定是添加操作。对于询问操作,L>0 且不超过当前序列的长度。


输出格式

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


数据范围1.png

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<stack>
#include<algorithm>
#include<vector>
#include<utility>
#include<deque>
#include<unordered_map>
#define INF 0x3f3f3f3f
#define mod 1000000007
#define endl '\n'
#define eps 1e-6
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline int lowbit(int x) { return x & -x; }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 200010;
int m, p;
struct Node {
  int l, r;
  int v;
}tr[N * 4];
void pushup(int u) { // 由子节点的信息计算父节点的信息
  tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
}
void build(int u, int l, int r) { //建树
  tr[u].l = l, tr[u].r = r; 
  if (l == r)return;
  int mid = l + r >> 1;
  build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
int query(int u, int l, int r) { //查询操作
  if (tr[u].l >= l && tr[u].r <= r)return tr[u].v; //树中节点已经被完全包含在[l,r]中
  int mid = tr[u].l + tr[u].r >> 1;
  int v = 0;
  if(l > mid)return query(u << 1 | 1,l,r);
    else if(r <= mid)return query(u << 1,l,r);
    else{
        int a = query(u << 1,l,r);
        int b = query(u << 1 | 1, l, r);
        return max(a,b);
    }
  return v;
}
void modify(int u, int x, int v) { //u表示当前线段树区间 x表示待修改的位置 v表示修改的值
  if (tr[u].l == x && tr[u].r == x)tr[u].v = v;
  else {
    int mid = tr[u].l + tr[u].r >> 1;
    if (x <= mid)modify(u << 1, x, v);
    else modify(u << 1 | 1, x, v);
    pushup(u);
  }
}
int main() {
  int n = 0;
  int last = 0;
  scanf("%d%d", &m, &p);
  build(1, 1, m);
  char op[2];
  int x = 0;
  while (m--) {
    scanf("%s%d", op, &x);
    if (op[0] == 'Q') {
      last = query(1, n - x + 1, n); //查询最后x个数
      printf("%d\n", last);
    }
    else {
      modify(1, n + 1, (last + x) % p);//修改第n+1个数 相当于在最后插入一个数
      ++n;
    }
  }
  return 0;
}


目录
相关文章
|
5月前
|
C++
线段树的单点修改
线段树的单点修改
34 0
|
3月前
|
算法 测试技术 C#
【单调栈 】LeetCode321:拼接最大数
【单调栈 】LeetCode321:拼接最大数
|
4月前
【每日一题Day157】LC1574删除最短的子数组使剩余数组有序 | 双指针 + 二分查找
【每日一题Day157】LC1574删除最短的子数组使剩余数组有序 | 双指针 + 二分查找
17 0
|
6月前
|
算法
OJ题库:奇偶数排序(使奇数全部都位于偶数前面)
OJ题库:奇偶数排序(使奇数全部都位于偶数前面)
34 0
leetcode-每日一题1403. 非递增顺序的最小子序列(贪心)
时间复杂度:O(n logn) 其中n时数组长度,对数组进行排序需要O(n logn)的时间,对数组进行遍历需要O(n)的时间
75 0
leetcode-每日一题1403. 非递增顺序的最小子序列(贪心)
Leetcode-每日一题769. 最多能完成排序的块(贪心)
需要怎么分割序列才是个问题,题目其实给了提示因为序列里的数只能是[0, n-1]所以选择[l, r] 连续的序列中的数一定是 [l, r] 这段区间的数字,所以我们只需要遍历数组,去找这段区间内最大的数字,即边界值r,因为他才是决定边界的数字,每次我们到达了r这个位置就表示下一段区间。
49 0
Leetcode-每日一题769. 最多能完成排序的块(贪心)