题意:给定n C k 和序列ai(1-n) 求最长的区间长度 使得 该区间中所有出现的元素 的个数为0或>=k 所有数字都在1-C的范围内
题解:
如果右端点固定,对于每种元素,可行的左端点下标是两段连续的区间。
对于每种元素,将它的可行左端点区间在线段树中加一。
当右端点右移的时候,维护 C种元素的可行左端点。
查询时只需要询问线段树中最小的、值为C 的下标即可。
画个图思路就很清晰了 非常好的线段树题
注意维护最值下标的方式
#include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define ll long long #define lson l,m,pos<<1 #define rson m+1,r,pos<<1|1 #define pb push_back #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// #define inf 0x3f3f3f3f const int N=1e5+5; int t[N<<2],col[N<<2],x[N<<2]; int C,k,n,m; vector<int>v[N]; void up(int pos) { t[pos]=max(t[pos<<1],t[pos<<1|1]); x[pos]=(t[pos]==t[pos<<1])?x[pos<<1]:x[pos<<1|1]; } void down(int pos) { if(col[pos]) { t[pos<<1]+=col[pos]; t[pos<<1|1]+=col[pos]; col[pos<<1]+=col[pos]; col[pos<<1|1]+=col[pos]; col[pos]=0; } } void build(int l,int r,int pos) { x[pos]=l;col[pos]=0; if(l==r){t[pos]=0;return ; } int m=(l+r)>>1;build(lson);build(rson);up(pos); } void upsum(int L,int R,int v,int l,int r,int pos) { if(L>R)return ; if(L<=l&&r<=R){ col[pos]+=v;t[pos]+=v;return ; } int m=(l+r)>>1;down(pos); if(L<=m)upsum(L,R,v,lson); if(R>m)upsum(L,R,v,rson); up(pos); } int qsum(int L,int R,int l,int r,int pos) { if(L<=l&&r<=R) { return t[pos]==C?x[pos]:0; } int m=(l+r)>>1;down(pos); if(L<=m)//这里一定要注意细节 { int t=qsum(L,R,lson); if(t)return t; } if(R>m)return qsum(L,R,rson); return 0; } int c; int main() { while(cin>>n>>C>>k) { rep(i,1,C+1)v[i].clear(),v[i].pb(0); build(1,n,1); int ans=0; rep(i,1,n) { RI(c); upsum(i,i,C-1,1,n,1); upsum(v[c].back()+1,i-1,-1,1,n,1); v[c].pb(i); int p=(v[c].size()-k-1); if(p>=0) upsum(v[c][p]+1,v[c][p+1],1,1,n,1); int j=qsum(1,n,1,n,1); if(!j)continue; ans=max(ans,i-j+1); } cout<<ans<<endl; } return 0; }