【最小区间问题】 RQM 和 线段树

范围最小值问题,利用进行预处理可以做到nlogn的处理和1的查询。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<stack>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define MAXD (1 << 10)
#define MAX_SIZE 1000 + 10
int d[MAXD][MAXD];
void RMQ_init(const vector<int>&A){
    int  n = A.size();
    for(int i = 0 ; i < n ; i++) d[i][0] = A[i];
    for(int j = 1 ; (1 << j) < n ; j++)
        for(int i = 0 ; i + (1 << j ) - 1 < n ; i++){
            d[i][j] = min(d[i][j - 1],d[i + (1 << (j- 1))][j - 1]);
    }
}
int RMQ(int L,int R){
    int k = 0;
    while((1 << (k + 1)) <= (R - L + 1)) k++;
    return min(d[L][k],d[R - (1 << k) + 1][k]);
}
int main(){
    int n;
    vector<int>arr;
    scanf("%d",&n);
    for(int i = 0 ; i < n ; i++){
        int t;
        scanf("%d",&t);
        arr.push_back(t);
    }
    RMQ_init(arr);
    int l,r;
    while(scanf("%d%d",&l,&r) != EOF){
        int ans = RMQ(l,r);
        printf("The min number in (%d,%d) is %d\n",l,r,ans);
    }
}
利用线段树实现RQM,可以做到一遍查询一遍进行改点。

查询说白了就是顺着结点不断往下分区间,当当前的区间被包含在[ql,q2](所求最小值的所在区间)的时候,进行return。

插入的时候更简单了,将A[p] = v,那么不断的往下分区间,知道区间 L = R (也就是 L = R = p)的时候return

#include <vector>
#include <list>
#include <map>
#include <string>
#include <set>
#include <cstring>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define maxd 1 << 10
#define INF  1 << 30
int minv[maxd];
int v,p;
int ql,qr;  /*查询[ql,qr]区间内的最小值*/
int query(int o,int L,int R){
    int M = L + (R - L) / 2,ans = INF;
    if(ql <= L && R <= qr)
        return minv[o];
    else if(ql <= M)
        ans = min(ans,query(o * 2 , L ,M));
    else if(M < qr)
        ans = min(ans,query(o * 2 + 1,M + 1, R));
    return ans;
}
void update(int o,int L,int R){ /*我们修改A[p] = v,o代表当前的结点,L,R代表当前结点的区间范围*/
    int M = L + (R - L)/2;
    if(L == R)
        minv[o] = v;
    else{
        if(p <= M)  /*如果这个点在左子树区间*/
            update(o * 2,L,M);
        else
            update(o * 2 + 1,M + 1,R);
        minv[o] = min(minv[o * 2],minv[o * 2 + 1]);
    }
}
int main(){
    int n,m;
    scanf("%d",&n);
    for(int i = 0 ; i < n ; i++){
        p = i + 1;
        scanf("%d",&v);
        update(1,1,n);
    }
    char str[10];
    while(scanf("%s",str) != EOF){
        if(str[0] == 'A'){
              scanf("%d%d",&p,&v);
              update(1,0,n);
        }
        else {
            scanf("%d%d",&ql,&qr);
            int ans = query(1,1,n);
            printf("%d\n",ans);
        }
    }
    return 0;
}

你可能感兴趣的:(【最小区间问题】 RQM 和 线段树)