RMQ模版总结
相关链接:http://blog.csdn.net/niushuai666/article/details/6624672
简介:RMQ有点像线段树,预处理的时间复杂度是nlogn,每次询问为O(1),所以,对于多次查找值不变的区间最大最小值具有非常高的效率。
相关变量:a数组,maxsum数组代表最大值,minsum代表最小值。
maxsum[i][j]的含义:从i开始。连续2^j个元素的最大值。比如,[1,0] ,代表从i=1开始,2^0=1个元素,也就是1,1 最大值即本身。
初始化:
注意一点,从1到n还是从0到n-1
将maxsum[i][0] = minsum[i][0] = a[i];
然后状态转移方程:状态转移方程F[i, j]=max(F[i,j-1], F[i + 2^(j-1),j-1])。
代码:
1 void RMQ(int num) //预处理->O(nlogn) 2 { 3 for(int i=1;i<=num;i++) 4 maxsum[i][0] = minsum[i][0] = a[i]; 5 for(int j = 1; j < 20; ++j) 6 for(int i = 1; i <= num; ++i) //如果是从0~n-1,这里i的循环变成从0~num-1; 7 if(i + (1 << j) - 1 <= num) 8 { 9 maxsum[i][j] = max(maxsum[i][j - 1], maxsum[i + (1 << (j - 1))][j - 1]); //加小括号因为+-优先级高 10 minsum[i][j] = min(minsum[i][j - 1], minsum[i + (1 << (j - 1))][j - 1]); 11 } 12 }
状态转移的实质:倍增。
查询代码:
1 int query(int l,int r) 2 { 3 int k=0; 4 while((1<<(k+1))<(r-l+1)) 5 k++; 6 int MIN=min(minsum[l][k],minsum[r-(1<<k)+1][k]); 7 int MAX=max(maxsum[l][k],maxsum[r-(1<<k)+1][k]); 8 return t-tt; //最大和最小差值 9 }
部分代码参考:飘过的小牛