题意:给定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; }