动态最值
minmax
有一个包含n个元素的数组,要求实现以下操作:
DELETE k:删除位置k上的数。右边的数往左移一个位置。
QUERY i j:查询位置i~j上所有数的最小值和最大值。
例如有10个元素:
位置 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
元素 | 1 | 5 | 2 | 6 | 7 | 4 | 9 | 3 | 1 | 5 |
QUERY 2 8的结果为2 9。依次执行DELETE 3和DELETE 6(注意这时删除的是原始数组的元素7)后数组变为:
位置 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
元素 | 1 | 5 | 6 | 7 | 4 | 3 | 1 | 5 |
QUERY 2 8的结果为1 7。
【输入】
输入文件minmax.in第一行包含两个数n, m,表示原始数组的元素个数和操作的个数。第二行包括n个数,表示原始数组。以下m行,每行格式为1 k或者2 i j,其中第一个数为1表示删除操作,为2表示询问操作。
【输出】
输出文件minmax.out对每个询问操作输出一行,包括两个数,表示该范围内的最小值和最大值。
【样例输入】
10 4
1 5 2 6 7 4 9 3 15
2 2 8
1 3
1 6
2 2 8
【样例输出】
2 9
1 7
【限制】
50%的数据满足1<=n, m<=104,删除操作不超过100个
100%的数据满足1<=n, m<=106, 1<=m<=106
对于所有的数据,数组中的元素绝对值均不超过109
解析:
很容易看出此题用线段树做。。。
其实对于query操作很容易维护,但考虑到delete操作,因为删除元素后下标变动,所以此处采用一个相对的动态区间来维护。
我们对每个结点维护三个值:min,max,sum。
每次删除元素后,将该节点的min设为一个不可能的极大值,将max设为极小值,将sum设为0。每次通过递归向上逐层update。
query区间(a,b)时: 如果b<左儿子的sum就query左儿子。。。
如果a>左儿子的sum就query右儿子,此时的区间为(a-左儿子的sum,b-左儿子的sum)。。。
否则当区间跨节点时,分别query区间(a,左儿子的sum);(1,b-左儿子的sum)。
每次query时,分别取当前节点的min取最小,max取最大。。。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1000010;
const int inf=2000000000;
int n,m,Min,Max,a[maxn];
struct
{
int minn,maxx,sum;
}tree[4*maxn+20];
void update(int p)
{
tree[p].minn=min(tree[p<<1].minn,tree[(p<<1)+1].minn);
tree[p].maxx=max(tree[p<<1].maxx,tree[(p<<1)+1].maxx);
tree[p].sum=tree[p<<1].sum+tree[(p<<1)+1].sum;
}
void build(int p,int l,int r)
{
if(l==r)
{
tree[p].minn=tree[p].maxx=a[l];
tree[p].sum=1;
return ;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build((p<<1)+1,mid+1,r);
update(p);
}
void readdata()
{
freopen("minmax.in","r",stdin);
freopen("minmax.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
build(1,1,n);
}
void de_le_te(int p,int l,int r,int k)
{
if(l==r)
{
tree[p].minn=inf;
tree[p].maxx=-inf;
tree[p].sum=0;
return ;
}
int mid=(l+r)>>1;
if(k<=tree[p<<1].sum)de_le_te(p<<1,l,mid,k);
else de_le_te((p<<1)+1,mid+1,r,k-tree[p<<1].sum);
update(p);
}
void query(int p,int l,int r,int a,int b)
{
if(b-a+1==tree[p].sum)
{
Min=tree[p].minn;
Max=tree[p].maxx;
return;
}
int mid=(l+r)>>1;
if(b<=tree[p<<1].sum)
{
query(p<<1,l,mid,a,b);
return;
}
if(a>tree[p<<1].sum)
{
query((p<<1)+1,mid+1,r,a-tree[p<<1].sum,b-tree[p<<1].sum);
return;
}
query(p<<1,l,mid,a,tree[p<<1].sum);
int min1=Min; int max1=Max;
query((p<<1)+1,mid+1,r,1,b-tree[p<<1].sum);
int min2=Min;int max2=Max;
Min=min(min1,min2);
Max=max(max1,max2);
}
void work()
{
int k,a,b;
for(int i=1;i<=m;i++)
{
int op;
scanf("%d",&op);
if(op==1)
{
scanf("%d",&k);
de_le_te(1,1,n,k);
}
if(op==2)
{
scanf("%d%d",&a,&b);
query(1,1,n,a,b);
printf("%d %d\n",Min,Max);
}
}
}
int main()
{
readdata();
work();
return 0;
}