简要题意

你需要维护一个序列 \(a\),有 \(q\) 个操作,支持:

  • 1 l r x 将 \([l,r]\) 赋值为 \(x\)。
  • 2 l r 询问 \([l,r]\) 的最小值。

为了加大难度,\(a\) 不会直接告诉你,但是会告诉你一个长度为 \(n\) 的序列 \(b\) 和一个整数 \(k\),\(a\) 是将 \(b\) 复制 \(k\) 遍依次拼接而成。

\(1 \leq n,q \leq 10^{5},1 \leq k \leq 10^{4},1 \leq b_i \leq 10^9,1 \leq l_i \leq r_i \leq nk\)

思路

如果直接求出 \(a\),那么时间复杂度和空间复杂度(都是 \(O(nk)\))不能接受。

我发现,如果没有修改,那么只需要用一个 ST 表即可,具体操作如下:

  • 如果 \((r-l+1)\geq n\),那么一定包含所有 \(b\) 中的元素,直接返回 \(b[1,n]\) 的最小值。
  • 如果 \((l-1)\bmod n+1>(r-1)\bmod n+1\),那么这个区间是跨区块的,如图:

(红色为 \(b\) 块,蓝色为询问 \([l,r]\),黑色为数值)

那么就是相对应的后缀最小值和前缀最小值的最小值。

  • 剩下的情况是完全在 \(b\) 块中,ST 表查询。

如果带上修改呢?我们可以打一个标记,如果这个区间有修改,那么直接读取修改后的结果,否则走上述过程。这一步可以使用动态开点线段树完成。

不过我的动态开点线段树总是会 TLE 掉一些点,由于本题数据随机,我们使用 ODT 替换掉动态开点线段树,就可以 AC 了。

时间复杂度均摊 \(O(n\log n+q\log nk)\),可以通过本题。

代码

#include<bits/stdc++.h>
#pragma GCC optimize("Ofast", "inline", "-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
using namespace std; const int N=100005;
int n,m,k,f[N][25],lg[N]= {-1},pre[N],suf[N];
int min_=INT_MAX,min_ans=INT_MAX; int st(int l,int r){
int logg=lg[r-l+1];
return min(f[l][logg],f[r-(1<<logg)+1][logg]);
} int solve(int l,int r) {
if(r-l+1>=n){// 如果包含整个块,那么最小值一定是 min(b[1],...,b[n])
return min_;
}
l=(l-1)%n+1; // 转成块内坐标
r=(r-1)%n+1;// 转成块内坐标
if(l>r){// 如果不在同一个块,直接返回右半块+左半块
return min(pre[r],suf[l]);
}
return st(l,r); // 如果在同一个块,ST表查询
} struct node {
int l,r;
mutable int v;
bool covered;
node(int ls,int rs=-1,int vv=0,bool coverevd=0){
l=ls,r=rs,v=vv,covered=coverevd;
}
bool operator<(const node &a)const {
return this->l<a.l;
}
}; set<node>s; set<node>::iterator split(int p) {// 分裂区间
if(p>n*k)return s.end();
set<node>::iterator it=--s.upper_bound(node(p,0,0,0));
if((*it).l==p)return it;
int l=(*it).l,r=(*it).r,v=(*it).v;
bool covered=(*it).covered;
s.erase(it);
s.insert(node(l,p-1,v,covered));
return s.insert(node(p,r,v,covered)).first;
} void assign(int l,int r,int v) { // 区间赋值
set<node>::iterator rs=split(r+1),ls=split(l);
s.erase(ls,rs);
s.insert(node(l,r,v,1));
min_ans=min(min_ans,v);
} int query(int l,int r) {
int ans=INT_MAX;
set<node>::iterator rs=split(r+1),ls=split(l);
for(set<node>::iterator it=ls; it!=rs; ++it) {
bool covered=(*it).covered;
if(covered) { // 如果被覆盖了,就直接用覆盖的值
ans=min(ans,(*it).v);
} else { // 如果没有被覆盖,就去 ST 表中查询
ans=min(ans,solve((*it).l,(*it).r));
}
if(ans==min_ans)break; // 如果已经查到全序列最小值,就直接返回
}
return ans;
} int main() {
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) {
scanf("%d",&f[i][0]);
}
pre[0]=suf[n+1]=INT_MAX;
for(int i=1;i<=n;i++) {
pre[i]=min(pre[i-1],f[i][0]);
lg[i]=lg[i>>1]+1;
min_=min(min_,f[i][0]);
min_ans=min(min_ans,f[i][0]);
}
for(int i=n;i>=1;i--) {
suf[i]=min(suf[i+1],f[i][0]);
}
for(int j=1;j<=20;j++) {
for(int i=1;i<=n+1-(1<<j);i++){
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
s.insert(node(1,n*k,min_,0));
scanf("%d",&m);
for(int i=1;i<=m;i++) {
int op,l,r,x;
scanf("%d%d%d",&op,&l,&r);
if(op==1) {
scanf("%d",&x);
assign(l,r,x);
} else {
printf("%d\n",query(l,r));
}
}
return 0;
}

CF803G Periodic RMQ Problem的更多相关文章

  1. CF803G - Periodic RMQ Problem 动态开点线段树 或 离线

    CF 题意 有一个长度为n × k (<=1E9)的数组,有区间修改和区间查询最小值的操作. 思路 由于数组过大,直接做显然不行. 有两种做法,可以用动态开点版本的线段树,或者离线搞(还没搞)( ...

  2. Codeforces 803G Periodic RMQ Problem 线段树

    Periodic RMQ Problem 动态开点线段树直接搞, 我把它分成两部分, 一部分是原来树上的, 一部分是后来染上去的,两个部分取最小值. 感觉有点难写.. #include<bits ...

  3. codeforces 803G Periodic RMQ Problem

    codeforces 803G Periodic RMQ Problem 题意 长度为\(1e5\)的数组复制\(1e4\)次,对新的数组进行区间覆盖和区间最小值查询两种操作,操作次数\(1e5\). ...

  4. AC日记——Periodic RMQ Problem codeforces 803G

    G - Periodic RMQ Problem 思路: 题目给一段序列,然后序列复制很多次: 维护序列很多次后的性质: 线段树动态开点: 来,上代码: #include <cstdio> ...

  5. (WAWAWAWAWAWAW) G. Periodic RMQ Problem

    没有联通门 : Codeforces G. Periodic RMQ Problem /* Codeforces G. Periodic RMQ Problem MMP 什么动态开点线段树啊 ... ...

  6. Codeforces 803 G. Periodic RMQ Problem

    题目链接:http://codeforces.com/problemset/problem/803/G 大致就是线段树动态开节点. 然后考虑到如果一个点还没有出现过,那么这个点显然未被修改,就将这个点 ...

  7. Codeforces 803G Periodic RMQ Problem ST表+动态开节点线段树

    思路: (我也不知道这是不是正解) ST表预处理出来原数列的两点之间的min 再搞一个动态开节点线段树 节点记录ans 和标记 lazy=-1 当前节点的ans可用  lazy=0 没被覆盖过 els ...

  8. BZOJ 3489: A simple rmq problem

    3489: A simple rmq problem Time Limit: 40 Sec  Memory Limit: 600 MBSubmit: 1594  Solved: 520[Submit] ...

  9. BZOJ3339 Rmq Problem

    [bzoj3339]Rmq Problem Description Input Output Sample Input 7 5 0 2 1 0 1 3 2 1 3 2 3 1 4 3 6 2 7 Sa ...

  10. bzoj 3489: A simple rmq problem k-d树思想大暴力

    3489: A simple rmq problem Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 551  Solved: 170[Submit][ ...

随机推荐

  1. 一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)

    这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 1.分布式架构下,Session共享有什么方案 2.简述你对RPC.RMI的理解 3.分布式id生成方案 4.分布式锁解决 ...

  2. 鼠标悬浮上去显示小手CSS

    鼠标悬浮上去显示小手CSS只需要添加一句css代码即可 cursor:pointer;

  3. 谣言检测(RDCL)——《Towards Robust False Information Detection on Social Networks with Contrastive Learning》

    论文信息 论文标题:Towards Robust False Information Detection on Social Networks with Contrastive Learning论文作 ...

  4. Optional对象

    Optional对象 Optional 类是一个可以为null的容器对象,用于简化Java中对空值的判断处理,以防止出现各种空指针异常. 静态方法-of 必须确定对象不为null 在使用of封装成op ...

  5. 2022春每日一题:Day 18

    题目:[JSOI2007]字符加密 很常见的做法,破环为链,然后以2n为总长再后缀排序,然后对于SA[i] < n 的,说明第i小后缀的编号是小于n的,也就是说,以i开头的编号是合法的,那么输出 ...

  6. Go语言核心36讲51

    你好,我是郝林,今天我们继续分享程序性能分析基础的内容. 在上一篇文章中,我们围绕着"怎样让程序对CPU概要信息进行采样"这一问题进行了探讨,今天,我们再来一起看看它的拓展问题. ...

  7. 07#Web 实战:实现 GitHub 个人主页项目拖拽排序

    实现效果图 GitHub 和 Gitee 个人主页中可以对自己的项目进行拖拽排序,于是我就想自己实现一个.本随笔只是记录一下大概的实现思路,如果感兴趣的小伙伴可以通过代码和本随笔的说明去理解实现过程. ...

  8. windows 搭建iis文件服务器

    1.运行打开控制面板->程序->启用或关闭Windows功能,勾选下面所有的选项. 注意,必须安装功能所需文件. 等待 关闭即可. 2.在控制面板找到管理工具,不同版本的Windows不尽 ...

  9. oracle 分析函数——ration_to_report 求占有率(百分比)

    oracle 的分析函数有很多,但是这个函数总是会忘记,我想通过这种方式能让自己记起来,不至于下次还要百度. 创表.表数据(平时练手的表): prompt PL/SQL Developer impor ...

  10. Datawhale组队学习_Task04:详读西瓜书+南瓜书第5章

    第5章 神经网络 5.1 神经元模型 基本定义:神经网络是由具有适应性的简单单元组成的广泛并行互联的网络,它的组织能够模拟生物神经系统对真实世界物体所做出的交互反应. M-P神经元模型:   在此模型 ...