线段树的常规操作,可以维护最大值,最小值,区间和。
而线段树的相关实现不仅能用数组,也经常使用结构体。
题目来源:http://poj.org/problem?id=3264
每天挤奶时,农夫John的N头奶牛(1≤N≤50,000头)总是按照相同的顺序排列。一天,农夫约翰决定和几头牛组织一场极限飞盘游戏。为了简单起见,他将从挤奶阵容中挑选一系列连续的奶牛来玩这个游戏。然而,为了让所有的奶牛都能玩得开心,它们的身高不应该相差太多。
农民John列出了Q(1≤Q≤200,000)头奶牛的身高(1≤身高≤1,000,000)。对于每一组,他希望您确定组中最矮和最高的牛之间的身高差异。
Input
第一行:两个空格分隔的整数N和Q
第二行到第N+1行:第i+1行包含一个整数,表示第i头奶牛的高度
第N+2行到第N+Q+1行:每行包含空格隔开的两个整数A、B(1≤A≤B≤N),表示奶牛从A到B的范围
Output
每行包含一个整数,是对每组范围的回答,表示范围内最高和最矮奶牛之间的高度差
Sample Input
6 3
1
7
3
4
2
5
1 5
4 6
2 2
Sample Output
6
3
0
要求同时维护最大值和最小值,所以用结构体更加方便。
struct node{
int minn;
int maxx;
}tree[maxn*4];
建树:
void build(int root,int l,int r){
if(l==r)
tree[root].minn=tree[root].maxx=arr[l];
else{
int mid=(l+r)/2;
int lson=root*2;
int rson=root*2+1;
build(lson,l,mid);
build(rson,mid+1,r);
tree[root].maxx=max(tree[lson].maxx,tree[rson].maxx);
tree[root].minn=min(tree[lson].minn,tree[rson].minn);
}
}
没有更新操作,不用写,直接查询
ll query(int root,int l,int r,int L,int R,int fla){//fla是开口,方便查询最大和最小,就没必要写两个函数
if(fla){
if(L<=l&&R>=r)
return tree[root].max;
int mid=(l+r)/2;
int lson=root*2;
int rson=root*2+1;
ll sum1=0,sum2=0;
if(L<=mid)
sum1=query(lson,l,mid,L,R,fla);
if(R>mid)
sum2=query(rson,mid+1,r,L,R,fla);
return max(sum1,sum2);
}
else{
if(L<=l&&R>=r)
return tree[root].max;
int mid=(l+r)/2;
int lson=root*2;
int rson=root*2+1;
ll sum1=0,sum2=0;
if(L<=mid)
sum1=query(lson,l,mid,L,R,fla);
if(R>mid)
sum2=query(rson,mid+1,r,L,R,fla);
return min(sum1,sum2);
}
}
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rep(i,a,b)for(int i=a;i<=b;i++)
#define rep1(i,a,b)for(int i=a;i<b;i++)
using namespace std;
const int maxn=2e6+5;
const int INF = 1e9;
int n,m;
int L,R;
int arr[maxn];
struct node{
int maxx;
int minn;
}tree[4*maxn];
void build(int root,int l,int r){
if(l==r)
tree[root].minn=tree[root].maxx=arr[l];
else{
int mid=(l+r)/2;
int lson=root*2;
int rson=root*2+1;
build(lson,l,mid);
build(rson,mid+1,r);
tree[root].maxx=max(tree[lson].maxx,tree[rson].maxx);
tree[root].minn=min(tree[lson].minn,tree[rson].minn);
}
}
ll query(int root,int l,int r,int L,int R,int fla){//fla是开口,方便查询最大和最小,就没必要写两个函数
if(fla){
if(L<=l&&R>=r)
return tree[root].max;
int mid=(l+r)/2;
int lson=root*2;
int rson=root*2+1;
ll sum1=0,sum2=0;
if(L<=mid)
sum1=query(lson,l,mid,L,R,fla);
if(R>mid)
sum2=query(rson,mid+1,r,L,R,fla);
return max(sum1,sum2);
}
else{
if(L<=l&&R>=r)
return tree[root].max;
int mid=(l+r)/2;
int lson=root*2;
int rson=root*2+1;
ll sum1=0,sum2=0;
if(L<=mid)
sum1=query(lson,l,mid,L,R,fla);
if(R>mid)
sum2=query(rson,mid+1,r,L,R,fla);
return min(sum1,sum2);
}
}
int main(){
//int cnt=1;
scanf("%d%d",&n,&m);
rep(i,1,n)
scanf("%d",&arr[i]);
build(1,1,n);
while(m--){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",query(1,1,n,x,y,1)-query(1,1,n,x,y,0));
}
}