printf("区间%d到%d的最大值为:%d\n",a,b,Query_max(a,b));
       printf("区间%d到%d的最小值为:%d\n",a,b,Query_min(a,b));
       printf("区间%d到%d的最大值和最小值只差为:%d\n",a,b,Query_max(a,b)-
Query_min(a,b));
   }
   return 0;
}
2、求区间内出现次数最多的数字出现的次数! 
对上升序列如:1 1 2 2 2 3 3 4 5 5 … 统计区间出现次数最多数个数。 
我们可以构造一个b[]数组, 
if(a[i]==a[i-1])b[i]=b[i-1]+1; 
else b[i]=1; 
这样对上述例子,b[]数组有1 2 1 2 3 1 2 1 1 2 
那么对询问区间[l,r],如果l在数与数交界处,那么直接查询l,r区间最大值。 
否则要知道与a[l]相同延伸到end,那么这个区间大小end-l+1,与rmq(end+1,r)取最大值就是答案。
#include 
using namespace std;
const int maxn=100017;
int num[maxn],f[maxn],MAX[maxn][20];
int n;
int max(int a,int b){
    return a>b?a:b;
}
int rmq_max(int l,int r){
    if(l>r)
        return 0;
    int k=log2((double)(r-l+1));
    return max(MAX[l][k],MAX[r-(1<            }
 
        }
        init();
        for(int i=1;i<=q;i++) {
            scanf("%d%d",&a,&b);
            int t=a;
            while(t<=b&&num[t]==num[t-1]){
                t++;
            }
            int cnt=rmq_max(t,b);
            int ans=max(t-a,cnt);
            printf("%d\n",ans);
        }
    }
    return 0;
}
RMQ求区间gcd 
 f [ l , r ]=gcd($a_l,a_{l+1},…,a_r$),问f [ l , r ]的值和有多少对(L,R)使得f [ L, R ] = f [ l , r ]。
#include
using namespace std;
#define LL long long
int dp[100010][32];
int a[100010];
int n,m,g,j;
int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
 
void rmq_init(){
    for(int j=1;j<=n;j++) dp[j][0]=a[j];
    for(int i=1;(1<mp;
void setTable(){
    mp.clear();
    for(int i=1;i<=n;i++){
         g=dp[i][0],j=i;  
         while(j<=n){
            int l=j,r=n;
            while(l>1;
                if(rmq_qui(i,mid)==g) l=mid;
                else r=mid-1;
            }
            mp[g]+=l-j+1;  //相当于二分枚举相加
            j=l+1;
            g=rmq_qui(i,j);
         }
    }
}
 
int main(){
    int t,l,r;
    int cas=1;
    scanf("%d",&t);
    while(t--){
        printf("Case #%d:\n",cas++);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        rmq_init();
        setTable();
        scanf("%d",&m);
        for(int i=0;i
using namespace std;
int n,m,a[400][400];
int dp[400][400][20][20];
int p;
int r1,c1,r2,c2,k1,k2,ans;
 
int main(){
    scanf("%d%d",&n,&m);  //二维区间的范围
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
            dp[i][j][0][0]=a[i][j];  //初始化
        }
    }
    int u1=0,u2=0;
    while((1<<(u1+1))<=n) u1++;
    while((1<<(u2+1))<=m) u2++;
    for(int i=1;i<=n;i++){
        for(int k=1;k<=u2;k++)
        for(int j=1;j+(1<<(k-1))<=m;j++){  //列建立RMQ
            dp[i][j][0][k]=max(dp[i][j][0][k-1],dp[i][j+(1<<(k-1))][0][k-1]);
        }
    }
    for(int i=1;i<=m;i++){
        for(int k=1;k<=u1;k++){
            for(int j=1;j+(1<<(k-1))<=n;j++){   //行建立RMQ
                dp[j][i][k][0]=max(dp[j][i][k-1][0],dp[j+(1<<(k-1))][i][k-1][0]);
,
查
询
复
杂
度
还
有
一
种
做
法
是
把
每
一
行
当
作
一
维
区
间
,
求
最
大
值
建
表
            }   
        }
    }
    for(int i=1;i<=u1;i++){
        for(int j=1;j<=u2;j++){
            for(int k=1;k+(1<<(i-1))<=n;k++){
                for(int p=1;p+(1<<(j-1))<=m;p++){   //行列合并
                    dp[k][p][i][j]=max(dp[k][p][i][j],dp[k][p][i-1][j-1]);
                    dp[k][p][i][j]=max(dp[k][p][i][j],dp[k+(1<<(i-1))][p][i-1][j-1]);
                    dp[k][p][i][j]=max(dp[k][p][i][j],dp[k][p+(1<<(j-1))][i-1][j-1]);
                    dp[k][p][i][j]=max(dp[k][p][i][j],dp[k+(1<<(i-1))][p+(1<<(j-1))]
[i-1][j-1]);
                }
            }
        }
    }
    scanf("%d",&p);
    while(p--){
        scanf("%d%d%d%d",&r1,&c1,&r2,&c2);//矩形的两个对角线顶点
        k1=k2=0;
        while((1<<(k1+1))<=(r2-r1+1)) k1++;  //等于int(log2(r2-r1+1))
        while((1<<(k2+1))<=(c2-c1+1)) k2++;  //等于int(log2(c2-c1+1))
        ans=0;
        //下面相当于分成四块矩形 
        ans=max(ans,dp[r1][c1][k1][k2]);//从(r1,c1)开始长度为2^k1和2^k2
        ans=max(ans,dp[r2-(1<
using namespace std;
typedef long long ll;
const int maxn = 1000005;
struct TREE {
    int tree[maxn * 4];  // 线段树
    int lz[maxn * 4];    // 延迟标记
 
    void init() {  //初始化
        memset(tree, 0, sizeof(tree));
        memset(lz, 0, sizeof(lz));
    }
 
    // 创建线段树
    void build(int root, int l, int r) {
        if (l == r) {
            scanf("%d", &tree[root]);
            return;
        }