题意:给定Q(1 ≤ Q≤ 200,000)个数A1,A2… AQ,,多次求任一区间Ai–Aj中最大数和最小数的差。
思路:1、线段树。节点要存放区间内的最大值和最小值。
线段树建立也可以不使用指针,而用数组代替:若根节点下标为0,假设线段树上某节点下标为i,则其左子节点下标为i *2 + 1, 右子节点下标为i * 2+ 2。若根节点为1,则左子树为i*2,右子树为i*2+1。
2、RMQ,就是裸的最大最小RMQ不需多解释。
指针建树代码:
#include <stdio.h>
#include <string.h>
#define N 200005
#define MIN 0x7fffffff
#define MAX -MIN
typedef struct node{
int left,right;//区间起点和终点
int min,max;//本区间里的最大最小值
struct node *lson,*rson;
}Tree;
int n,q,resmin,resmax,mid;
Tree t[N*2+1];
Tree *root,*alloc;
int min(int a,int b){
if(a<b)
return a;
return b;
}
int max(int a,int b){
if(a>b)
return a;
return b;
}
int getmid(Tree *x){
return (x->left+x->right)/2;
}
void create(Tree *r,int L,int R){
r->left= L;
r->right = R;
r->max = MAX;
r->min = MIN;
if(L!=R){
mid=getmid(r);
r->lson = ++alloc;
create(r->lson,L,mid);
r->rson = ++alloc;
create(r->rson,mid+1,R);
}
}
void insert(Tree *r,int index,int x){//将第i个数,其值为v,插入线段树
mid=getmid(r);
r->min = min(r->min,x);
r->max = max(r->max,x);
if(r->left==index && r->right==index)
return ;
if(index <= mid)
insert(r->lson,index,x);
else
insert(r->rson,index,x);
}
void query(Tree *r,int L,int R){//查询区间[L,R]中的最小值和最大值,如果更优就记在全局变量里
mid = getmid(r);
if(resmax>r->max && resmin<r->min)//剪枝
return ;
if(L == r->left && R == r->right){
resmin = min(resmin,r->min);
resmax = max(resmax,r->max);
}else if(R <= mid)
query(r->lson,L,R);
else if(L > mid)
query(r->rson,L,R);
else{
query(r->lson,L,mid);
query(r->rson,mid+1,R);
}
}
int main(){
freopen("a.txt","r",stdin);
while(scanf("%d %d",&n,&q)!=EOF){
int i,a,b,num;
root = alloc = t;
create(root,1,n);
for(i = 1;i<=n;i++){
scanf("%d",&num);
insert(root,i,num);
}
for(i = 1;i<=q;i++){
scanf("%d %d",&a,&b);
resmin = MIN;
resmax = MAX;
query(root,a,b);
printf("%d\n",resmax-resmin);
}
}
return 0;
}
数组建树代码:
#include <stdio.h>
#include <string.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define N 200005
struct node{
int left,right,up,down;
}t[N*2+1];
int n,q,big,sma;
int midnum(int a,int b){
return (a+b)>>1;
}
void create(int id,int a,int b){
int mid = midnum(a,b);
t[id].left = a;
t[id].right = b;
t[id].up = 0;
t[id].down = 0x3fffffff;
if(a == b)
return;
create(id*2, a, mid);
create(id*2+1, mid+1, b);
}
void insert(int root,int id,int x){//将序号为id位置插入数字x
t[root].up = max(t[root].up , x);
t[root].down = min(t[root].down , x);
if(t[root].right==id && t[root].left==id)
return;
if(id<=(t[root].left+t[root].right)/2)
insert(root*2, id, x);
else
insert(root*2+1, id, x);
}
void query(int root,int a,int b){
int mid = midnum(t[root].left,t[root].right);
if(t[root].left == a && t[root].right==b){
big = max(big,t[root].up);
sma = min(sma,t[root].down);
return ;
}
if(b<=mid)
query(root*2, a, b);
else if(a>mid)
query(root*2+1, a, b);
else{
query(root*2, a, mid);
query(root*2+1, mid+1, b);
}
}
int main(){
int i,x,y;
scanf("%d %d",&n,&q);
create(1,1,n);
for(i = 1;i<=n;i++){
scanf("%d",&x);
insert(1,i,x);
}
for(i = 1;i<=q;i++){
big = 0;
sma = 0x3fffffff;
scanf("%d %d",&x,&y);
query(1,x,y);
printf("%d\n",big-sma);
}
}
RMQ:
#include <cstdio>
#include <cstring>
#include <cmath>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define N 50005
#define Q 200005
using namespace std;
int dmax[N][20],dmin[N][20],s[N];
int n,q;
void st(int n){
int i,j,k = log((double)(n+1))/log(2.);
for(j = 1;j<=n;j++)
dmax[j][0] = dmin[j][0] = s[j];
for(j = 1;j<=k;j++)
for(i = 1;i+(1<<j)-1<=n;i++){
dmax[i][j] = max(dmax[i][j-1], dmax[i+(1<<(j-1))][j-1]);
dmin[i][j] = min(dmin[i][j-1], dmin[i+(1<<(j-1))][j-1]);
}
}
int querymax(int a,int b){
int k = log((double)(b-a+1))/log(2.);
return max(dmax[a][k], dmax[b-(1<<k)+1][k]);
}
int querymin(int a,int b){
int k = log((double)(b-a+1))/log(2.);
return min(dmin[a][k], dmin[b-(1<<k)+1][k]);
}
int main(){
int i,a,b,x,y;
scanf("%d %d",&n,&q);
for(i = 1;i<=n;i++)
scanf("%d",&s[i]);
st(n);
for(i = 0;i<q;i++){
scanf("%d %d",&a,&b);
x = querymin(a,b);
y = querymax(a,b);
printf("%d\n",y-x);
}
return 0;
}