- 线段树求静态RMQ问题
-
首先,对于每个数 i i i 显然要维护,以 i i i 结尾的最长不重复子段的长度
维护 s t a r t i start_i starti 表示以 i i i 结尾,最长不重复子段的开始位置
那么, i − s t a r t i + 1 i-start_i+1 i−starti+1 就是以 i i i 结尾的最长不重复子段的长度维护 s t a r t i start_i starti :
1 ∣ 1| 1∣. s t a r t i start_i starti 肯定在上一个 a i a_i ai 出现的位置 + 1 +1 +1 的位置及以后
2 ∣ 2| 2∣. s t a r t i start_i starti肯定在 f i − 1 f_{i-1} fi−1 的位置及以后 (如果上一个都有重复那么下一个一定有重复)所以 s t a r t [ i ] = m a x ( f [ i − 1 ] , l s t [ a [ i ] ] + 1 ) start[i]=max(f[i-1],lst[a[i]]+1) start[i]=max(f[i−1],lst[a[i]]+1) 即为满足要求
cin>>n>>q;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
start[i]=max(start[i-1],lst[a[i]]+1);
lst[a[i]]=i;
}
-
而对于每个问题 [ L , R ] [L,R] [L,R]
在 s t a r t i start_i starti 已知的情况下,令 f ( i ) f(i) f(i) 表示在区间内以 i i i 结尾的最长合法子段长度,分以下几种情况:对于 L ≤ i ≤ R L\leq i \leq R L≤i≤R :
1 ∣ 1| 1∣ s t a r t i start_i starti 在 L L L 左侧
那么 f ( i ) = i − L + 1 f(i)=i-L+1 f(i)=i−L+12 ∣ 2| 2∣ s t a r t i start_i starti 在 L L L 及 L L L 右侧
那么 f ( i ) = i − s t a r t i + 1 f(i)=i-start_i+1 f(i)=i−starti+1最终对于询问的结果应该为 m a x ( f L . . . . f R ) max(f_L....f_R) max(fL....fR)
//60pts
while(q--)
{
int l,r,res=0;
cin>>l>>r;
for(int i=l;i<=r;i++)
{
if(start[i]<l) res=max(res,i-l+1);
else res=max(res,i-start[i]+1);
}
cout<<res<<endl;
}
问题相当于 静态维护区间 f i f_i fi 最大值
考虑到 f i f_i fi 的不减性,我们可以用 l o w e r lower lower_ b o u n d bound bound 二分查找出第一个 s t a r t i ≤ L start_i \leq L starti≤L 的 p o s pos pos ,那么 p o s − 1 pos-1 pos−1 就是位置最大的 s t a r t i < L start_i < L starti<L 的数
如上文所述,对于 L ≤ i ≤ R L\leq i \leq R L≤i≤R ,若 s t a r t i start_i starti 在 L L L 左侧,那么 f ( i ) = i − L + 1 f(i)=i-L+1 f(i)=i−L+1
那么这个数在所有的 s t a r t i < L start_i < L starti<L 的数中的 f ( i ) f(i) f(i) 也一定是最大的为 p o s − L + 1 pos-L+1 pos−L+1
而对于 i > = p o s i>=pos i>=pos 的情况,即 s t a r t i > = L start_i >= L starti>=L, f ( i ) = i − s t a r t i + 1 f(i)=i-start_i+1 f(i)=i−starti+1 ,用 S T ST ST 表 或 线段树维护
#include<bits/stdc++.h>
#define lson pos<<1
#define rson pos<<1|1
#define mid ((l+r)>>1)
using namespace std;
const int MAXN=1e6+5;
int n,q,a[MAXN],start[MAXN],lst[MAXN],f[MAXN],st[MAXN][20];
void build()
{
for(int i=1;i<=n;i++) st[i][0]=f[i];
for(int j=1;j<=log2(n);j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=max(st[i][j-1], st[i+(1<<(j-1))][j-1]);
}
int query(int l,int r)
{
int t=log2(r-l+1);
return max(st[l][t],st[r-(1<<t)+1][t]);
}
int main()
{
freopen("norep.in","r",stdin);
freopen("norep.out","w",stdout);
cin>>n>>q;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
start[i]=max(start[i-1],lst[a[i]]+1);
lst[a[i]]=i;
}
for(int i=1;i<=n;i++)
f[i]=i-start[i]+1;
build();
while(q--)
{
int l,r,res=0;
cin>>l>>r;
int pos=lower_bound(start+l,start+r,l)-start;
if(start[r]<l) res=max(res,r-l+1);
else
{
if(pos-1>=l) res=max(res,pos-1-l+1);
if(pos<=r) res=max(res,query(pos,r));
}
cout<<res<<endl;
}
return 0;
}
#include<bits/stdc++.h>
#define lson pos<<1
#define rson pos<<1|1
#define mid ((l+r)>>1)
using namespace std;
const int MAXN=1e6+5;
int n,q,a[MAXN],start[MAXN],lst[MAXN],f[MAXN],tree[MAXN<<4];
void pushup(int pos)
{
tree[pos]=max(tree[lson],tree[rson]);
}
void build(int pos,int l,int r)
{
if(l==r) {tree[pos]=f[l]; return ;}
build(lson,l,mid);
build(rson,mid+1,r);
pushup(pos);
}
int query(int pos,int l,int r,int x,int y)
{
if(x<=l && r<=y) return tree[pos];
int res=0;
if(x<=mid) res=max(res,query(lson,l,mid,x,y));
if(y>mid) res=max(res,query(rson,mid+1,r,x,y));
return res;
}
int main()
{
freopen("norep.in","r",stdin);
freopen("norep.out","w",stdout);
cin>>n>>q;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
start[i]=max(start[i-1],lst[a[i]]+1);
lst[a[i]]=i;
}
for(int i=1;i<=n;i++)
f[i]=i-start[i]+1;
build(1,1,n);
while(q--)
{
int l,r,res=0;
cin>>l>>r;
int pos=lower_bound(start+l,start+r,l)-start;
if(start[r]<l) res=max(res,r-l+1);
else
{
if(pos-1>=l) res=max(res,pos-1-l+1);
if(pos<=r) res=max(res,query(1,1,n,pos,r));
}
cout<<res<<endl;
}
return 0;
}