poj2823 Sliding Window(单调队列)

这篇博客介绍了如何利用单调队列和线段树两种数据结构解决寻找数字序列中长度为K的区间内最小值与最大值的问题。文章详细展示了两种方法的实现代码,并通过实例解释了它们的工作原理。单调队列法通过维护最大值和最小值的单调队列,线段树法则通过构建并查询线段树来高效获取区间最值。这两种方法都具有较高的时间效率,适用于大规模数据处理。
摘要由CSDN通过智能技术生成

在这里插入图片描述
在这里插入图片描述

题意:

给定一个长度为 N N N 的数字序列,要求你求出每个长度为 K K K 的区间内的最小值与最大值。

单调队列做法:

const int N = 1e6 + 10;
const int mod = 998244353;

int a[N], maxx[N], minn[N], queue1[N], queue2[N];//queue存位置
int i, n, k, front1, front2, tail1, tail2, cnt;

int main()
{
    sdd(n, k);
    cnt = front1 = front2 = tail1 = tail2 = 1;//front头指针,tail尾指针
    rep(i, 1, n)
    {
        sd(a[i]);
        if (i - queue1[front1] >= k)
            front1++;
        if (i - queue2[front2] >= k)
            front2++;
        if (a[i] >= a[queue1[tail1]])
            while (a[i] >= a[queue1[tail1]] && tail1 >= front1)
                tail1--;
        queue1[++tail1] = i;
        if (a[i] <= queue2[tail2])
            while (a[i] <= a[queue2[tail2]] && tail2 >= front2)
                tail2--;
        queue2[++tail2] = i;
        if (i >= k)
        {
            maxx[cnt] = a[queue1[front1]];
            minn[cnt++] = a[queue2[front2]];
        }
    }
    for (int i = 1; i + k - 1 <= n; i++)
        printf("%d%c", minn[i], i + k - 1 == n ? '\n' : ' ');
    for (int i = 1; i + k - 1 <= n; i++)
        printf("%d%c", maxx[i], i + k - 1 == n ? '\n' : ' ');
    return 0;
}

线段树做法:

const int N = 1e6 + 50;
int a[N];
int ans1[N], ans2[N];

struct node
{
    int left, right, mid;
    int maxn, minn;
} w[4 * N];

int build(int l, int r, int root)
{
    if (l == r)
    {
        w[root].left = w[root].right = l;
        w[root].maxn = a[l];
        w[root].minn = a[l];
        return w[root].maxn;
    }
    w[root].left = l;
    w[root].right = r;
    w[root].mid = (l + r) / 2;
    build(l, w[root].mid, 2 * root);
    build(w[root].mid + 1, r, 2 * root + 1);
    w[root].maxn = max(w[2 * root].maxn, w[2 * root + 1].maxn);
    w[root].minn = min(w[2 * root].minn, w[2 * root + 1].minn);
    return w[root].maxn;
}

int querymax(int l, int r, int root)
{
    if (w[root].left == l && w[root].right == r)
    {
        return w[root].maxn;
    }
    else if (l > w[root].mid)
    {
        return querymax(l, r, 2 * root + 1);
    }
    else if (r <= w[root].mid)
    {
        return querymax(l, r, 2 * root);
    }
    else
    {
        return max(querymax(l, w[root].mid, 2 * root), querymax(w[root].mid + 1, r, 2 * root + 1));
    }
}

int querymin(int l, int r, int root)
{
    if (w[root].left == l && w[root].right == r)
    {
        return w[root].minn;
    }
    else if (l > w[root].mid)
    {
        return querymin(l, r, 2 * root + 1);
    }
    else if (r <= w[root].mid)
    {
        return querymin(l, r, 2 * root);
    }
    else
    {
        return min(querymin(l, w[root].mid, 2 * root), querymin(w[root].mid + 1, r, 2 * root + 1));
    }
}

int main()
{
    int n, k;
    sdd(n, k);
    rep(i, 1, n)
        sd(a[i]);
    build(1, n, 1);
    for (int i = 1; i + k - 1 <= n; i++)
    {
        ans1[i] = querymin(i, i + k - 1, 1);
        ans2[i] = querymax(i, i + k - 1, 1);
    }
    for (int i = 1; i + k - 1 <= n; i++)
        printf("%d%c", ans1[i], i + k - 1 == n ? '\n' : ' ');
    for (int i = 1; i + k - 1 <= n; i++)
        printf("%d%c", ans2[i], i + k - 1 == n ? '\n' : ' ');
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值