poj 2823 Sliding Window (单调队列 or 线段树)


今天看到别人讨论单调队列,感觉好久没写了想复习一下。说道单调队列最经典的题目之一就是这个"Sliding Window"了吧。
开一个数组,每次以存原数组下标的方式保存数据。以队首最大为例,每次新加一个元素,先把队尾小于新数据的全部去掉,然后新增这个元素(当然实际存的是这个数在原数组的下标)。


#include<iostream>
#include<cstdio>
using namespace std;

#define MAXN 1000010

int num[MAXN];
int p[MAXN], q[MAXN];
int ans1[MAXN], ans2[MAXN];

int main()
{
int n, m;
int p1, p2, q1, q2;
while(~scanf("%d%d", &n, &m))
{
p1 = p2 = q1 = q2 = 1;
for(int i = 1; i <= n; i++)
scanf("%d", &num[i]);
for(int i = 1; i <= n; i++)
{
while(p2 >= p1 && num[p[p2]] >= num[i])p2--;
p[++p2] = i;
while(q2 >= q1 && num[q[q2]] <= num[i])q2--;
q[++q2] = i;
while(i - p[p1] >= m)p1++;
while(i - q[q1] >= m)q1++;
if(i >= m)
{
ans1[i] = num[p[p1]];
ans2[i] = num[q[q1]];
}
}
printf("%d", ans1[m]);
for(int i = m+1; i <= n; i++)
printf(" %d", ans1[i]);

putchar(10);

printf("%d", ans2[m]);
for(int i = m+1; i <= n; i++)
printf(" %d", ans2[i]);
}
return 0;
}

线段树版本

#include<iostream>
#include<algorithm>
using namespace std;

#define inf 0x3f3f3f3
#define MAXN 1000010
struct node
{
int l;
int r;
int max;
int min;
}tree[MAXN * 3];

int MAX[MAXN], MIN[MAXN];
int num[MAXN];

void build(int l, int r, int root)
{
tree[root].l = l;
tree[root].r = r;
if(l == r)
{
tree[root].max = tree[root].min = num[l];
return;
}
int mid = (l + r) >> 1;
build(l, mid, root<<1);
build(mid + 1, r, root<<1|1);
tree[root].max = max(tree[root<<1].max, tree[root<<1|1].max);
tree[root].min = min(tree[root<<1].min, tree[root<<1|1].min);
}

void query(int l, int r, int root, int &pos)
{
if(tree[root].l == l && tree[root].r == r)
{
MAX[pos] = max(MAX[pos], tree[root].max);
MIN[pos] = min(MIN[pos], tree[root].min);
return;
}
int mid = (tree[root].l + tree[root].r) >> 1;
if(r <= mid)
query(l, r, root<<1, pos);
else if(l > mid)
query(l, r, root<<1|1, pos);
else
{
query(l, mid, root<<1, pos);
query(mid+1, r, root<<1|1, pos);
}
}

int main()
{
int n, m;
while(~scanf("%d%d", &n, &m))
{
for(int i = 1; i <= n; i++)
{
scanf("%d", &num[i]);
MAX[i] = -inf;
MIN[i] = inf;
}
build(1, n, 1);
for(int i = 1; i <= n-m+1; i++)
{
query(i, i+m-1, 1, i);
}
for(int i = 1; i <= n-m+1; i++)
printf("%d ", MIN[i]);
putchar(10);
for(int i = 1; i <= n-m+1; i++)
printf("%d ", MAX[i]);
putchar(10);
}
return 0;
}



另一线段树版本(很好很强大)

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

#define inf 0x3f3f3f3
#define MAXN 1000010

int MAX[MAXN], MIN[MAXN];
int tree1[MAXN*3];
int tree2[MAXN*3];
int n, m, M;
int pos = 1;
int Max(int a, int b)
{
return a > b ? a : b;
}

int Min(int a, int b)
{
return a < b ? a : b;
}

void build()
{
for(M = 1; M <= n+1; M<<=1);
for(int i = M+1; i <= n+M; i++)
{
scanf("%d", &tree1[i]);
tree2[i] = tree1[i];
}
for(int i = M-1; i >= 1; i--)
{
tree1[i] = Max(tree1[i<<1], tree1[i<<1|1]);
tree2[i] = Min(tree2[i<<1], tree2[i<<1|1]);
}
}

void query(int s, int t)
{
int big = -inf;
int small = inf;
for(s = s + M -1, t = t + M + 1; s^t^1; s>>=1,t>>=1)
{
if(~s&1)
{
big = Max(big, tree1[s^1]);
small = Min(small, tree2[s^1]);
}
if(t&1)
{
big = Max(big, tree1[t^1]);
small = Min(small, tree2[t^1]);
}
}
printf("%d ", small);
MAX[pos] = big;
MIN[pos++] = small;
}

int main()
{
while(~scanf("%d%d", &n, &m))
{
build();
pos = 1;
for(int i = 1; i <= n-m+1; i++)
{
query(i, i+m-1);
}
for(int i = 1; i <= n-m+1; i++)
printf("%d ", MIN[i]);
putchar(10);
for(int i = 1; i <= n-m+1; i++)
printf("%d ", MAX[i]);
putchar(10);
}
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值