與眾不同 RMQ——ST表的運用
阿新 • • 發佈:2018-12-11
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; }