1. 程式人生 > >與眾不同 RMQ——ST表的運用

與眾不同 RMQ——ST表的運用

inline void ST(int n){
	int maxlog=log2(n);
	for(int j=1;j<=maxlog;++j)
		for(int i=1;i+(1<<j-1)-1<=n;++i)
			mx[i][j]=max(mx[i][j-1],mx[i+(1<<j-1)][j-1]);
}

預處理,本質是個dp,倍增求lca思想類似。

inline int Query(int l,int r){
	if(l>r)return 0;
	int maxlog=log2(r-l+1);
	return max(mx[l][maxlog],mx[r-(1<<maxlog)+1][maxlog]);
}

回答,就是左右兩邊拼起來,為了避免不漏,我們取最大的log。

Description

  A是某公司的CEO,每個月都會有員工把公司的盈利資料送給A,A是個與眾不同的怪人,A不注重盈利還是虧本,而是喜歡研究“完美序列”:連續的互不相同的序列。A想知道區間[L,R]之間最長的完美序列。

Input

  第一行兩個整數N,M(1<=N,M<=200000),N表示連續N個月,編號為0到N-1,M表示詢問的次數。第二行N個整數(絕對值不超過106),第i個數表示該公司第i個月的盈利值。接下來M行每行兩個整數L,R(0<=L<=R<=N-1),表示A詢問的區間。

Output

  輸出M行,每行一個整數對應詢問區間內的完美序列的最長長度。

Sample Input

9 2 2 5 4 1 2 3 6 2 4 0 8 2 6

Sample Output

6 5

設st[i]為當前數i的最長完美序列開頭位置,則st[i]=max(st[i-1],last[x]+1)。

對於詢問[l,r],直接用RMQ也許會出現st[x]<l的情況,我們要找到這個分界點,觀察st的遞推式,發現st單調不下降,於是二分求解分界點x。於是ans=max(x-l+1,RMQ(x,r))。

#include<bits/stdc++.h>
using namespace std;
const int Maxn=200005,Maxv=1000005;
int mx[Maxn][20];
int st[Maxn],last[Maxv*2];
inline void ST(int n){
	int maxlog=log2(n);
	for(int j=1;j<=maxlog;++j)
		for(int i=1;i+(1<<j-1)-1<=n;++i)
			mx[i][j]=max(mx[i][j-1],mx[i+(1<<j-1)][j-1]);
}
inline int Query(int l,int r){
	if(l>r)return 0;
	int maxlog=log2(r-l+1);
	return max(mx[l][maxlog],mx[r-(1<<maxlog)+1][maxlog]);
}
inline void findp(int &p,int l,int r){
	if(st[l]==l)return p=l,void();
	if(st[r]<=l)return p=r+1,void();
	int L=l,R=r;
	while(L<=R){
		int mid=L+R>>1;
		if(st[mid]<l)L=mid+1;
		else p=mid,R=mid-1;
	}
}
int main(){
	int n,m;scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		int x;scanf("%d",&x);
		st[i]=max(st[i-1],last[x+Maxv]+1);
		mx[i][0]=i-st[i]+1;
		last[x+Maxv]=i;
	}
	ST(n);
	for(int i=1;i<=m;++i){
		int l,r;scanf("%d%d",&l,&r);
		int p;findp(p,l+1,r+1);
		cout<<max(p-l-1,Query(p,r+1))<<'\n';
	}
	return 0;
}