P1440 求m区间内的最小值
解题思路
这道题目要求我们对于数列中的每一个元素,找到它前面m个元素(不足m个时从第一个开始)的最小值。这是一个典型的滑动窗口最小值问题,可以使用单调队列或线段树来解决。
题目提供的代码使用了线段树解法:
-
线段树构建:构建一个能够查询区间最小值的线段树
-
查询处理:对于每个元素a[i],查询区间[max(1,i-m), i-1]的最小值
-
特殊情况处理:第一个元素前面没有元素,直接输出0
线段树虽然查询时间复杂度为O(logn),但对于n=2e6的数据规模可能不够高效(理论上O(nlogn)可能勉强通过)。更优的解法是使用单调队列,可以达到O(n)的时间复杂度。
代码注释
#include<bits/stdc++.h> #define lc rt << 1 // 左子节点索引 #define rc rt << 1 | 1 // 右子节点索引 #define lson lc,l,mid // 左子树参数 #define rson rc,mid + 1,r // 右子树参数 #define ll long long using namespace std; const int N = 2e6 + 10, inf = 0x3f3f3f3f; // 线段树节点结构体,存储区间最大值(实际用于存最小值) struct node{ int maxx; // 变量名是maxx但实际用于存储最小值 }; node t[N << 2]; // 线段树数组 int n, m; int a[N]; // 原始数据数组 // 更新父节点的值(取左右子树的最小值) void pushup(int rt) { t[rt].maxx = min(t[lc].maxx, t[rc].maxx); } // 构建线段树 void build(int rt, int l, int r) { if(l == r) { // 叶子节点 t[rt].maxx = a[l]; // 存储单个元素值 return; } int mid = (l + r) / 2; // 计算中点 build(lson); // 构建左子树 build(rson); // 构建右子树 pushup(rt); // 更新当前节点 } // 区间查询最小值 int query(int rt, int l, int r, int x, int y) { if(r < x || y < l) return inf; // 区间无交集返回无穷大 if(x <= l && r <= y) return t[rt].maxx; // 完全包含直接返回 int mid = (l + r) / 2; // 返回左右子树查询结果的较小值 return min(query(lson, x, y), query(rson, x, y)); } int main() { cin >> n >> m; // 读取n和m for(int i = 1; i <= n; i++) scanf("%d", &a[i]); // 读取数列 build(1, 1, n); // 构建线段树 cout << 0 << endl; // 第一个元素前面没有数,输出0 for(int i = 2; i <= n; i++) // 从第二个元素开始处理 { int x, y; if(i < m){ // 前面不足m个元素 x = 1, y = i - 1; // 从第1个到前一个 } else { x = i - m, y = i - 1; // 正常情况取前m个 } printf("%d\n", query(1, 1, n, x, y)); // 查询并输出最小值 } return 0; }

浙公网安备 33010602011771号