南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进行比较,计算出两个人的杀敌数差值,用这种方法一方面能鼓舞杀敌数高的人,另一方面也算是批评杀敌数低的人,起到了很好的效果。
所以,南将军经常问军师小工第i号士兵到第j号士兵中,杀敌数最高的人与杀敌数最低的人之间军功差值是多少。
现在,请你写一个程序,帮小工回答南将军每次的询问吧。
注意,南将军可能询问很多次。
输入描述:
只有一组测试数据
第一行是两个整数N,Q,其中N表示士兵的总数。Q表示南将军询问的次数。(1<N<=100000,1<Q<=1000000)
随后的一行有N个整数Vi(0<=Vi<100000000),分别表示每个人的杀敌数。
再之后的Q行,每行有两个正正数m,n,表示南将军询问的是第m号士兵到第n号士兵。
输出描述:
对于每次询问,输出第m号士兵到第n号士兵之间所有士兵杀敌数的最大值与最小值的差。
样例输入:
复制
5 2
1 2 6 9 3
1 2
2 4
样例输出:
1
7
提示:
没有提示哦
来源:
经典改编
上传者:张云聪
思路:本来用的线段树做的,结果超限了,查了一下很多用的是RMQ算法过的,然后去学习了一下,RMQ这个算法适用于修改少,查询多的题
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
int minn[100010][20],maxx[100010][20];
void RMQ(int num)
{
for(int j=1;(1<<j)<=num;j++)
{
for(int i=1;i+(1<<j)-1<=num;i++)
{
minn[i][j]=min(minn[i][j-1],minn[i+(1<<j-1)][j-1]);
maxx[i][j]=max(maxx[i][j-1],maxx[i+(1<<j-1)][j-1]);
}
}
return ;
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
for(int a=1;a<=n;a++)
{
scanf("%d",&maxx[a][0]);
minn[a][0]=maxx[a][0];
}
RMQ(n);
while(q--)
{
int l,r,maxm,minm;
scanf("%d%d",&l,&r);
int k=(int)(log2(r-l+1));
maxm=max(maxx[l][k],maxx[r-(1<<k)+1][k]);
minm=min(minn[l][k],minn[r-(1<<k)+1][k]);
printf("%d\n",maxm-minm);
}
return 0;
}