题解 CF803G Periodic RMQ Problem
题意
给定一个长度为
- 区间推平
- 区间查询最小值
数据范围:
题解
又是一道 DS 妙题。
空间可以动态开点优化至
发现每次新建节点都要求出区间的最小值,考虑如何快速求出。
对于一个新建的节点,该区间是由
设区间为
- 当
时,此时一定包含了整个 序列,区间最小值为 。
- 当
且 时, 在同一 序列中,区间最小值为 。
- 当
且 时, 恰分布在两个 序列中的连续段,区间最小值为 。
于是可以对
感觉写下来有种分块的味道,整体还算小清新。
顺便提一嘴数组开的大小,因为下传标记时会开左右儿子的点,所以实际上还有一个常数
#include <bits/stdc++.h>
using namespace std;
namespace IO {
//read and write
} using namespace IO;
const int N = 1e5 + 10, M = 6e6 + 10, L = 20;
int n, k, q;
namespace RMQ {
int st[L][N];
void init() {
for(int i = 1; (1 << i) <= n; i++)
for(int j = 0; j + (1 << i) - 1 < n; j++)
st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << i - 1)]);
}
int Min(int l, int r) {
int len = log2(r - l + 1);
return min(st[len][l], st[len][r - (1 << len) + 1]);
}
} using namespace RMQ;
namespace SegmentTree {
int rt, ls[M], rs[M], mn[M], tag[M], cnt;
int newnode(int l, int r) {
++cnt;
if(r - l + 1 >= n) return mn[cnt] = Min(0, n - 1), cnt;
if(l / n == r / n) return mn[cnt] = Min(l % n, r % n), cnt;
return mn[cnt] = min(Min(l % n, n - 1), Min(0, r % n)), cnt;
}
void pushup(int x) { mn[x] = min(mn[ls[x]], mn[rs[x]]); }
void pushdown(int x, int l, int r) {
int mid = l + r >> 1;
if(!ls[x]) ls[x] = newnode(l, mid);
if(!rs[x]) rs[x] = newnode(mid + 1, r);
if(!tag[x]) return;
mn[ls[x]] = mn[rs[x]] = tag[ls[x]] = tag[rs[x]] = tag[x];
tag[x] = 0;
return;
}
void modify(int &x, int l, int r, int L, int R, int v) {
if(!x) x = newnode(l, r);
if(L <= l && r <= R) { mn[x] = tag[x] = v; return; };
pushdown(x, l, r);
int mid = l + r >> 1;
if(mid >= L) modify(ls[x], l, mid, L, R, v);
if(mid < R) modify(rs[x], mid + 1, r, L, R, v);
pushup(x);
}
int query(int &x, int l, int r, int L, int R) {
if(!x) x = newnode(l, r);
if(L <= l && r <= R) return mn[x];
pushdown(x, l, r);
int mid = l + r >> 1, res = 2e9;
if(mid >= L) res = min(res, query(ls[x], l, mid, L, R));
if(mid < R) res = min(res, query(rs[x], mid + 1, r, L, R));
return res;
}
} using namespace SegmentTree;
int main() {
n = read(), k = read();
for(int i = 0; i < n; i++) st[0][i] = read();
init();
q = read();
int opt, l, r, x;
while(q--) {
opt = read(), l = read() - 1, r = read() - 1;
if(opt == 1) x = read(), modify(rt, 0, n * k - 1, l, r, x);
else write(query(rt, 0, n * k - 1, l, r)), putc('\n');
}
flush();
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话