正题

题目链接:https://www.luogu.com.cn/problem/P3793


题目大意

给出\(n\)个数字的一个序列\(m\)次询问区间最大值

保证数据随机

\(1\leq n,m\leq 2\times 10^7\)


解题思路

使用\(ST\)表可以做到\(O(1)\)询问,但是预处理的时空复杂度都是\(O(n\log n)\),且自带大常数导致过不了。

如何加快预处理的时间,(因为是lxl的题目所以)考虑使用分块。每次询问可以分为整块的部分和不是整块的零散部分。

去掉没有跨块的情况,那么零散的部分就是块内前后缀最大值。然后整块的部分用\(ST\)表就好了。

那么没有跨块的情况是不是还需要给每个块维护一个\(ST\)表?这样空间还是过不了,其实可以考虑将没有跨块的情况按顺序每个块每个块离线处理,这样就可以过了。

但是数据保证随机,所以随机到同一个块内的概率是\(\frac{1}{T}\),也就是期望\(\sqrt n\)次,暴力处理是\(O(\sqrt n)\)的,所以直接暴力处理就可以了

时间复杂度\(O(n\log\sqrt n+m)\)。


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2e7+10;
namespace GenHelper{
unsigned z1,z2,z3,z4,b;
unsigned rand_()
{
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);
}
}
void srand(unsigned x)
{using namespace GenHelper;
z1=x; z2=(~x)^0x233333333U; z3=x^0x1234598766U; z4=(~x)+51;}
int read()
{
using namespace GenHelper;
int a=rand_()&32767;
int b=rand_()&32767;
return a*32768+b;
}
int n,m,a[N],lg[N],p[N],q[N],g[5000][13];
int L[5000],R[5000],pos[N];
unsigned s;
unsigned long long ans;
int AskT(int l,int r){
if(l>r)return 0;int z=lg[r-l+1];
return max(g[l][z],g[r-(1<<z)+1][z]);
}
int main()
{
scanf("%d%d%u",&n,&m,&s);
srand(s);
for(int i=1;i<=n;i++)a[i]=read();
int T=sqrt(n);
for(int i=1;i<=T;i++)
L[i]=R[i-1]+1,R[i]=i*T;
if(R[T]!=n)++T,L[T]=R[T-1]+1,R[T]=n;
for(int i=1;i<=T;i++){
for(int j=L[i];j<=R[i];j++)pos[j]=i,g[i][0]=max(g[i][0],a[j]);
p[L[i]]=a[L[i]];q[R[i]]=a[R[i]];
for(int j=L[i]+1;j<=R[i];j++)p[j]=max(p[j-1],a[j]);
for(int j=R[i]-1;j>=L[i];j--)q[j]=max(q[j+1],a[j]);
}
for(int j=1;(1<<j)<=T;j++)
for(int i=1;i+(1<<j)-1<=T;i++)
g[i][j]=max(g[i][j-1],g[i+(1<<j-1)][j-1]);
for(int i=2;i<=T;i++)lg[i]=lg[i>>1]+1;
for(int i=1;i<=m;i++){
int l=read(),r=read();
l=l%n+1;r=r%n+1;
if(l>r)swap(l,r);
int x=pos[l],y=pos[r];
int tmp=0;
if(x==y){
for(int i=l;i<=r;i++)
tmp=max(tmp,a[i]);
}
else{
tmp=AskT(x+1,y-1);
tmp=max(tmp,max(q[l],p[r]));
}
ans+=tmp;
}
printf("%llu\n",ans);
}

P3793-由乃救爷爷【分块,ST表】的更多相关文章

  1. Luogu3793 由乃救爷爷 分块、ST表

    传送门 因为昨天写暴力写挂在UOJ上用快排惨遭卡常,所以今天准备写一个卡常题消遣消遣,然后时间又垫底了QAQ 这道题显然需要支持一个\(O(N)\)预处理\(O(1)\)查询的ST表,显然普通的ST表 ...

  2. [洛谷P3793]由乃救爷爷

    题目大意:有$n(n\leqslant2\times10^7)$个数,$m(m\leqslant2\times10^7)$个询问,每次询问问区间$[l,r]$中的最大值.保证数据随机 题解:分块,处理 ...

  3. 【JZOJ5064】【GDOI2017第二轮模拟day2】友好城市 Kosarajo算法+bitset+ST表+分块

    题面 在Byteland 一共有n 座城市,编号依次为1 到n,这些城市之间通过m 条单向公路连接. 对于两座不同的城市a 和b,如果a 能通过这些单向道路直接或间接到达b,且b 也能如此到达a,那么 ...

  4. Luogu 3793 由乃救爷爷

    \(\verb|Luogu 3793 由乃救爷爷|\) rmq,数据随机 \(n,\ m\leq 2\times10^7\) lxl ST表 分块,大小设为 \(x\) 预处理每个块两端到块内每个点的 ...

  5. [bzoj4540][Hnoi2016][序列] (莫队算法+单调栈+st表)

    Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-1,ar.若1≤l≤s≤t≤r≤n,则称a ...

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

    Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插 ...

  7. CF1039E Summer Oenothera Exhibition 贪心、根号分治、倍增、ST表

    传送门 感谢这一篇博客的指导(Orzwxh) $PS$:默认数组下标为$1$到$N$ 首先很明显的贪心:每一次都选择尽可能长的区间 不妨设$d_i$表示在取当前$K$的情况下,左端点为$i$的所有满足 ...

  8. CF1039E Summer Oenothera Exhibition 根号分治,LCT,ST表

    CF1039E Summer Oenothera Exhibition LG传送门 根号分治好题. 可以先看我的根号分治总结. 题意就是给出长度为\(n\)的区间和\(q\)组询问以及一个\(w\), ...

  9. 【笔记】自学ST表笔记

    自学ST表笔记 说实话原先QBXT学的ST表忘的差不多了吧...... 我重新自学巩固一下(回忆一下) 顺便把原先一些思想来源的原博发上来 一.ST表简介 ST表,建表时间\(O(n\cdot log ...

随机推荐

  1. MySQL临时表与内存表

    在MySQL中有三种虚拟表:临时表.内存表.视图.下面简单介绍一下临时表和内存表的使用. 1.临时表 MySQL临时表在我们需要保存一些临时数据时是非常有用的.临时表在MySQL 3.23版本中添加. ...

  2. 链表LinkedList、堆栈Stack、集合Set

    链表LinkedList LinkedList 也像 ArrayList 一样实现了基本的 List 接口,但它在 List 中间执行插入和删除操作时比 ArrayList 更高效.然而,它在随机访问 ...

  3. OJ 注意事项

    1,检查指针是否有效,即是否为NULL 1 void OutputMaxAndMin(int * pInputInteger, int InputNum, int * pMaxValue, int * ...

  4. Promise.all()

    语法:Promise.all(iterable); 参数:iterable 一个可迭代对象,如 Array 或 String. 返回值:如果传入的参数是一个空的可迭代对象,则返回一个已完成(alrea ...

  5. 《手把手教你》系列技巧篇(二十三)-java+ selenium自动化测试-webdriver处理浏览器多窗口切换下卷(详细教程)

    1.简介 上一篇讲解和分享了如何获取浏览器窗口的句柄,那么今天这一篇就是讲解获取后我们要做什么,就是利用获取的句柄进行浏览器窗口的切换来分别定位不同页面中的元素进行操作. 2.为什么要切换窗口? Se ...

  6. 谈谈redis缓存击穿透和缓存击穿的区别,雪崩效应

    面试经历 在很长的一段时间里,我以为缓存击穿和缓存穿透是一个东西,直到最近去腾讯面试,面试官问我缓存击穿和穿透的区别:我回答它俩是一样的,面试官马上抬起头用他那细长的单眼皮眼睛瞪着我说:"你 ...

  7. mysqli的基本使用

    简单实例 面向过程方式 // 创建数据库连接 $connect = mysqli_connect('127.0.0.1', 'root', 'root', 'test', 8889); // 判读是否 ...

  8. 使用kubeadm安装kubernetes 1.21

    文章原文 配置要求 至少2台 2核4G 的服务器 本文档中,CPU必须为 x86架构 CentOS 7.8 或 CentOS Stream 8 安装后的软件版本为 Kubernetes v1.21.x ...

  9. JDK1.8源码(八)——java.lang.ThreadLocal类

    https://www.cnblogs.com/xdd666/p/14734047.html ThreadLocal https://www.cnblogs.com/yanfei1819/p/1473 ...

  10. python 回归分析

    一.线性回归 1 绘制散点图 import matplotlib.pyplot as plt x = [5,7,8,7,2,17,2,9,4,11,12,9,6] y = [99,86,87,88,1 ...