1. 程式人生 > >並不對勁的st表

並不對勁的st表

math putchar 個數 string return 個性 ring () using

對於帶修改的區間求和能做到O(n log n)預處理,O(log n)查詢;而不帶修改的可以做到O(n)預處理,O(1)查詢。那麽不帶修改的區間最值能做到O(1)查詢嗎?

區間最值有這樣一個性質:對於一段區間的兩個子區間,如果它們覆蓋了整個區間(可以有重疊部分),那麽這兩段區間各自的最大(或最小)值的最大(或最小)值就等於整個區間的最大(或最小)值。

這樣的話,可以倍增地求出從每個位置開始的2的x次方的區間最值,預處理每個數的log。查詢l-r這一段區間時按如圖所示的方式合並就行了。

技術分享圖片

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define maxn 100010 
using namespace std;
int read()
{
	int f=1,x=0;char ch=getchar();
	while(isdigit(ch)==0 && ch!=‘-‘)ch=getchar();
	if(ch==‘-‘)f=-1,ch=getchar();
	while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
	return x*f;
}
void write(int x)
{
	int ff=0;char ch[15];
	if(x<0)
	{
		x=-x;
		putchar(‘-‘);
	}
	while(x)ch[++ff]=(x%10)+‘0‘,x/=10;
	if(ff==0)putchar(‘0‘);
	while(ff)putchar(ch[ff--]);
	putchar(‘\n‘);
}
struct ST
{
	int st[maxn][20],logx[maxn],two[maxn];
	int n,q,l,r;
	void ask()
	{
		l=read(),r=read();
		write(max(st[l][logx[r-l+1]],st[r-two[r-l+1]+1][logx[r-l+1]]));
	}
	void work()
	{
		n=read(),q=read();
		for(int i=1,j=1,k=0;i<=n;i++)
	    {
	    	st[i][0]=read();
			if((j<<1)<=i)j<<=1,k++;
			logx[i]=k;
			two[i]=j;
		} 
		for(int i=1;(1<<i)<=n;i++)
		{
			for(int j=1;j+(1<<(i))-1<=n;j++)
			{
				st[j][i]=max(st[j][i-1],st[j+(1<<(i-1))][i-1]);
			//	cout<<st[j][i]<<" "; 
			}//cout<<endl;
		}
		while(q--)
		{
			ask();
		}
	}//1 2 3 4 5
}t;
int main()
{
	t.work();
	return 0;
}/*
8 8
9 3 1 7 5 6 0 8
1 6
1 5
2 7
2 6
1 8
4 8
3 7
1 8
*/

  

並不對勁的st表