Luogu 3793 由乃救爷爷

\(\verb|Luogu 3793 由乃救爷爷|\)

rmq,数据随机

\(n,\ m\leq 2\times10^7\)

lxl ST表


分块,大小设为 \(x\)

预处理每个块两端到块内每个点的前缀 \(\max\) 和后缀 \(\max\)

预处理块间ST表

数据随机

就成了期望 \(O(n)\) 的rmq

重点是没人卡你,卡还不一定卡的住,还要冒着被暴力AC的风险

然后就愉悦地~

#include <bits/stdc++.h>
using namespace std;

#define get(x) (((x) + 63) >> 6)
typedef unsigned uint;
const int maxn = 2e7 + 10;
int n, m, K, tot, a[maxn], lef[maxn], rig[maxn], lg[maxn >> 6], val[20][maxn >> 6];

namespace GenHelper {
  uint z1, z2, z3, z4, b;
  inline uint rnd() {
    b = ((z1 << 6) ^ z1) >> 13;
    z1 = ((z1 & 4294967294u) << 18) ^ b;
    b = ((z2 << 2) ^ z2) >> 27;
    z2 = ((z2 & 4294967288u) << 2) ^ b;
    b = ((z3 << 13) ^ z3) >> 21;
    z3 = ((z3 & 4294967280u) << 7) ^ b;
    b = ((z4 << 3) ^ z4) >> 12;
    z4 = ((z4 & 4294967168u) << 13) ^ b;
    return (z1 ^ z2 ^ z3 ^ z4);
  }
}

inline void srand(uint x) {
  using namespace GenHelper;
  z1 = x;
  z2 = (~x) ^ 0x233333333u;
  z3 = x ^ 0x1234598766u;
  z4 = (~x) + 51;
}

inline int read() {
  using namespace GenHelper;
  int a = rnd() & 32767;
  int b = rnd() & 32767;
  return a << 15 | b;
}

inline int query(int l, int r) {
  if (l > r) return 0;
  int tmp = lg[r - l + 1];
  return max(val[tmp][l], val[tmp][r - (1 << tmp) + 1]);
}

int main() {
  scanf("%d %d %d", &n, &m, &K);
  srand(K);
  for (int i = 1; i <= n; ++i) {
    a[i] = read();
    val[0][get(i)] = max(a[i], val[0][get(i)]);
  }
  tot = get(n);
  for (int i = 2; i <= tot; ++i) {
    lg[i] = lg[i >> 1] + 1;
  }
  for (int i = 1, lst = 0; i <= n; ++i) {
    lef[i] = lst = max(a[i], lst);
    if (!(i & 63)) lst = 0;
  }
  for (int i = n, lst = 0; i; --i) {
    if (!(i & 63)) lst = 0;
    rig[i] = lst = max(a[i], lst);
  }
  for (int i = 1; i < 21; ++i) {
    for (int j = 1; j + (1 << i) <= tot; ++j) {
      val[i][j] = max(val[i - 1][j], val[i - 1][j + (1 << (i - 1))]);
    }
  }
  unsigned long long ans = 0;
  for (int q = 1, l, r, L, R, res; q <= m; ++q) {
    l = read() % n + 1;
    r = read() % n + 1;
    if (l > r) l ^= r ^= l ^= r;
    L = get(l), R = get(r), res = 0;
    if (L == R) {
      for (int i = l; i <= r; ++i) {
        res = max(res, a[i]);
      }
    } else {
      res = max(max(rig[l], lef[r]), query(L + 1, R - 1));
    }
    ans += res;
  }
  printf("%llu", ans);
  return 0;
}

原文地址:https://www.cnblogs.com/Juanzhang/p/10463796.html

时间: 2024-11-08 10:48:58

Luogu 3793 由乃救爷爷的相关文章

Luogu3793 由乃救爷爷 分块、ST表

传送门 因为昨天写暴力写挂在UOJ上用快排惨遭卡常,所以今天准备写一个卡常题消遣消遣,然后时间又垫底了QAQ 这道题显然需要支持一个\(O(N)\)预处理\(O(1)\)查询的ST表,显然普通的ST表是做不到的,因为预处理的时间太长了 于是分块优化掉ST表的预处理 约定\(L_i,R_i\)表示第\(i\)个块的左端点和右端点,\(be_i\)表示第\(i\)个数所在的块 对于每一个位置\(i\)预处理\(L_{be_i}\)到\(i\)的所有数的最大值\(lmax_i\)以及\(i\)到\(R

[luogu]P2279 [HNOI2003]消防局的设立[贪心]

[luogu]P2279 [HNOI2003]消防局的设立 题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状结构.如果基地A到基地B至少要经过d条道路的话,我们称基地A到基地B的距离为d. 由于火星上非常干燥,经常引发火灾,人类决定在火星上修建若干个消防局.消防局只能修建在基地里,每个消防局有能力扑灭与它距离不超过2的基地的火灾. 你的任务是计算

luogu P3799 妖梦拼木棒

二次联通门 : luogu P3799 妖梦拼木棒 /* luogu P3799 妖梦拼木棒 用一个桶存下所有的木棒 美剧两根短的木棒长度 后随便乘一乘就 好了.. */ #include <algorithm> #include <cstdio> #define Mod 1000000007 #define Max 5000 void read (int &now) { now = 0; register char word = getchar (); while (wo

[luogu P1967][NOIp2013]P1967 货车运输

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z

《欢乐颂》第二季来袭:程序员救美,邱莹莹终于找到靠谱男

<欢乐颂>前不久刚迎来大结局,大家就马上开始期待第二季了.都市剧那么多,却独独火了它.也许这部剧成功之处就在于它真实,因为大部分人都能从剧中找到现在或是曾经的自己. 现实生活中,我们大多都是像邱莹莹这样的普通人,羡慕曲筱绡,梦想做安迪,一直像关雎尔一样拼命努力,最后发现只是比樊胜美过得好一些.很多人讨厌邱莹莹的无知和冲动,但看到最后却发现,她虽然被公司辞退,却通过自己的网购经验,误打误撞把咖啡厅的工作做的有声有色. 你以为到这里,邱莹莹迎来了完美结局,故事就要结束了吗?NONONO,有一种故事

luogu 3126 回文的路径

https://www.luogu.org/problem/show?pid=3126 考虑dp,从两头走到中间. f[i][j][k][l]表示从左上角走到(i,j),从右下角走到(k,l),路径长度相等,所经过路径相同的方案数. 方程不再赘述. 考虑步数要相同,所以只要枚举步数和行就好. f[i][j][k]表示第一个点在第j行,第2个点在第k行,走i步的方案数. 所以得出方程f[i][j][k]=(f[i-1][j-1][k]+f[i-1][j][k+1]+f[i-1][j-1][k+1]

luogu P2018 消息传递

二次联通门 : luogu P2018 消息传递 /* luogu P2018 消息传递 树形dp 原来用优先队列做了一下, T了俩点 MMP 去看正解.. 复杂度一样好不好.. 每次到达一个点,记录其子树中所有的dp值 优先向大的一边转移 */ #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define INF 1e8 const int BUF

luogu P1966 火柴排队

二次联通门 : luogu P1966 火柴排队 /* luogu P1966 火柴排队 神TM逆序对... noip怎么这么坑啊.. 暴力都没得打 此题模拟考试时爆了0 做法 将A数组排序,由于B数组与A数组是一一对应的 那么B数组的位置也会发生相应的变化 此时B数组逆序数对数即为答案 */ #include <cstdio> #include <iostream> #include <algorithm> const int BUF = 123123123; cha

luogu P1941 飞扬的小鸟

二次联通门 : luogu P1941 飞扬的小鸟 /* luogu P1941 飞扬的小鸟 dp 向上飞是完全背包,向下掉就是01背包 分情况讨论一下 最后合并一下 */ #include <cstdio> #include <iostream> #include <cstring> const int BUF = 123123123; char Buf[BUF], *buf = Buf; inline void read (int &now) { for (