Longest Subarray
题意:一个数列,每个元素大小都在1到C之间,求一个最长的子串,满足在这个子串中1到C之间的每个数字要么出现0次,要么出现至少K次。
题解:(i)从1到n枚举右端点,维护一个(tree[j])表示在(i)为右端点时以(j)为左端点可行的个数(这里的可行是指对于1到C之间的某一个数是否可行,即(j)到(i)之间(X)的个数是否满足题意,(Xepsilon(1,C)))。那么对于固定的(i)显然当(tree[j]==C)时([j,i])是一个可行区间,找出最小的(j)即可. 上述操作在线段树上维护.
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,c,k,a[100005];
int tree[maxn*4],tag[maxn*4];
inline int ls(int x){
return x<<1;
}
inline int rs(int x){
return x<<1|1;
}
void change(int root,int del){
tree[root]+=del;
tag[root]+=del;
}
void pushdown(int root,int l,int r){
if(!tag[root]) return;
int mid=(l+r)>>1;
change(ls(root),tag[root]);
change(rs(root),tag[root]);
tag[root]=0;
}
void update(int root,int l,int r,int il,int ir,int del){
if(r<il||l>ir) return;
if(l>=il&&r<=ir) {
tree[root] += del;
tag[root] += del;
return;
}
pushdown(root,l,r);
int mid=(l+r)>>1;
update(ls(root),l,mid,il,ir,del);
update(rs(root),mid+1,r,il,ir,del);
tree[root]=max(tree[ls(root)],tree[rs(root)]);
}
int ask(int root,int l,int r,int il,int ir){
if(r<il||l>ir) return -1;
if(tree[root]<c) return -1;
if(l==r) return l;
pushdown(root,l,r);
int mid=(l+r)>>1;
int tmp=ask(ls(root),l,mid,il,ir);
if(tmp>0) return tmp;
return ask(rs(root),mid+1,r,il,ir);
}
vector<int> pos[maxn];
int main(){
while(~scanf("%d%d%d",&n,&c,&k)) {
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=c;i++) {
pos[i].clear();
}
if(k==1){
printf("%d
",n); continue;
}
int nn=n*4;
for(int i=1;i<=nn;i++) tree[i]=0,tag[i]=0;
int ans=0;
for(int i=1;i<=n;i++){
pos[a[i]].push_back(i);
update(1,1,n,i,i,c-1);
int siz=pos[a[i]].size();
if(siz>=1){
int l=siz-2,r=siz-1;
if(l<0) l=1;
else l=pos[a[i]][l]+1;
r=pos[a[i]][r]-1;
if(l<=r) update(1,1,n,l,r,-1);
}
if(siz>=k){
int l=siz-k-1,r=siz-k;
if(l<0) l=1;
else l=pos[a[i]][l]+1;
r=pos[a[i]][r];
update(1,1,n,l,r,1);
}
int tmp=ask(1,1,n,1,i);
if(tmp>0) ans=max(ans,i-tmp+1);
}
printf("%d
",ans);
}
return 0;
}