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;
}