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

来源:互联网 发布:企业邮箱域名申请 编辑:程序博客网 时间:2024/05/17 00:14

范围最小值问题,利用进行预处理可以做到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 + 10int 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 << 30int 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;}

0 0
原创粉丝点击