题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6602
题意:
给你一个数组a,保证该数组中的每个数字属于[1,c],现在要你求一段最长的区间使得,在这个区间内,所有在1~c的数字要么不出现,要么出现超过k次。
做法:
很有意思的一个线段树啊真不好想。
假设我们枚举每一个右界R,那么对于在它左边的每一个出现的数字c,我们先找到它出现的第一个位置First_Pos_c和往前找到第k次出现的Kth_Pos_c,如果我们找到的区间要保证这个数字合法,那么我们找的L必须要在[1,Kth_Pos_c]和(First_Pos_c, R]之间,因为这样我们才能使得这个数字要么出现k次(前者),要么不出现(后者),这里注意我们区间的开闭关系。
所以我们就可以这样,对于每一个数字,我们都保存下它所出现的位置,然后我们去一个个的更新。对于一个数字没有出现的区间,我们把它加上1,或者是,已经有多出k次出现的数字,我们把从1到第前k次的位置也加1(注意每个数字都要加上一个初始的区间0-n+1,这样一个数字如果没有出现的话也能把贡献加上),枚举到当前位置的时候,我们要把前一段它没有出现的位置减掉,把下一段它没有出现的位置加上(这样在枚举右区间的时候它的影响才能被算上),然后去看看最左边的现在有c个数字的位置在哪里,如果存在就把这个区间的长度和答案进行更新即可。
#include <bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
#define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
using namespace std;
typedef long long ll;
const int maxn=100005;
int maxx[maxn<<2],laz[maxn<<2];
int n,c,k,pos[maxn],a[maxn];
vector<int> ve[maxn];
void deal(int rt,int v){
maxx[rt]+=v;
laz[rt]+=v;
}
void build(int l,int r,int rt){
maxx[rt]=laz[rt]=0;
if(l==r) return ;
int mid=(r+l)/2;
build(l,mid,lson);
build(mid+1,r,rson);
}
void push_down(int rt){
if(laz[rt]){
deal(lson,laz[rt]);
deal(rson,laz[rt]);
laz[rt]=0;
}
}
void update(int l,int r,int rt,int ql,int qr,int v){
if(qr<ql) return ;
if(ql<=l&&r<=qr){
deal(rt,v);
return ;
}
push_down(rt);
int mid=(r+l)/2;
if(ql<=mid) update(l,mid,lson,ql,qr,v);
if(qr>mid) update(mid+1,r,rson,ql,qr,v);
maxx[rt]=max(maxx[lson],maxx[rson]);
}
int query(int l,int r,int rt){
if(l==r) return l;
push_down(rt);
int mid=(r+l)/2,ret=-1;
if(maxx[lson]==c) ret=query(l,mid,lson);
else if(maxx[rson]==c) ret=query(mid+1,r,rson);
return ret;
}
void init(){
rep(i,1,c){
ve[i].clear();
ve[i].push_back(0);
}
build(1,n,1);
}
int main(){
while(~scanf("%d%d%d",&n,&c,&k)){
init();
rep(i,1,n) {
scanf("%d",&a[i]);
ve[a[i]].push_back(i);
}
rep(i,1,c) {
ve[i].push_back(n+1);
update(1,n,1,ve[i][0]+1,ve[i][1]-1,1);
pos[i]=0;
}
int ans=0;
for(int i=1;i<=n;i++){
int aim=a[i];
update(1,n,1,ve[aim][pos[aim]]+1,ve[aim][pos[aim]+1]-1,-1);
if(pos[aim]>=k) update(1,n,1,1,ve[aim][pos[aim]-k+1],-1);
pos[aim]++;
update(1,n,1,ve[aim][pos[aim]]+1,ve[aim][pos[aim]+1]-1,1);
if(pos[aim]>=k) update(1,n,1,1,ve[aim][pos[aim]-k+1],1);
int tmp=query(1,n,1);
if(tmp!=-1) ans=max(ans,i-tmp+1);
}
printf("%d\n",ans);
}
return 0;
}