这题是真的秀。。。我服了。。。线段树用好了,感觉什么都可以写。。。
题目大意:给你一个串,问满足以下条件的子串中最长的是多长:对于每个数字,要么在这个子串没出现过,要么出现次数超过k次。
我们对于每一个位置i,肯定希望往左找到最远满足条件的,然后维护一个最大值,岂不美哉?
那么我们该如何找到最远满足条件的???那么又该维护一些什么东西?
我们维护一个数组t[],t[j]=m表示从i位往左到j位置,满足条件的个数(要么为0个,要么大于等于k个),用线段树维护。
对于每个一个位置i,我们需要在当前位置加上C-1,代表从当前点,区间长度为0
我们每次讨论t[i]的时候就是将i位置作为右端点,因为a[i]=x,所以除x以外的其他数,左端点都可以是i位置,因为[i,i]这个区间内只有x出现了1次,其他都是出现0次,出现0次的肯定是可行的,所以先加上C-1(-1是因为i位置是否为x的可行左端点还需要进一步讨论)
然后我们考虑从i位置的数a[i],由于第i位出现了a[i],那么造成了当前位置到上一个位置和a[i]相等值的位置,这个区间以前是可以的,但是现在变得不可以。我们需要
从上一个位置到这个的值全部-1,代表a[i],不再这个区间可用。并且,我们从当前位置往前的k个a[i]的位置的到前k-1个a[i]的位置,这个位置以前是不可用的,但是由于右边新增加了一个a[i],这个区间将由不可用变成可用,那么在区间内部应该+1,代表这个值原来不可用,现在可用。
#include<bits/stdc++.h> #define LL long long #define lson rt<<1 #define rson rt<<1|1 using namespace std; const int maxx = 1e5+6; struct node{ int l,r; int laze,cnt; }tree[maxx<<2]; int a[maxx]; int pre[maxx]; int n,c,k; vector<int>G[maxx]; void push_down(int rt){ if (tree[rt].laze){ tree[lson].cnt+=tree[rt].laze; tree[rson].cnt+=tree[rt].laze; tree[lson].laze+=tree[rt].laze; tree[rson].laze+=tree[rt].laze; tree[rt].laze=0; } } void buildtree(int rt,int l,int r){ tree[rt].l=l; tree[rt].r=r; tree[rt].laze=0; tree[rt].cnt=0; if (l==r){ return; } int mid=(l+r)>>1; buildtree(lson,l,mid); buildtree(rson,mid+1,r); } void update(int rt,int ul,int ur,int w){ int l=tree[rt].l; int r=tree[rt].r; if(ul<=l && r<=ur){ tree[rt].cnt+=w; tree[rt].laze+=w; return ; } push_down(rt); int mid=(l+r)>>1; if (ur<=mid){ update(lson,ul,ur,w); }else if(ul>mid){ update(rson,ul,ur,w); }else { update(lson,ul,mid,w); update(rson,mid+1,ur,w); } tree[rt].cnt=max(tree[lson].cnt,tree[rson].cnt); } int query(int rt){ int l=tree[rt].l; int r=tree[rt].r; if(l==r){ return l; } push_down(rt); int mid=(l+r)>>1; if(tree[lson].cnt==c){ return query(lson); }else if(tree[rson].cnt==c){ return query(rson); }else { return -1; } } int main(){ while(~scanf("%d%d%d",&n,&c,&k)){ for(int i=1;i<=c;i++){ G[i].clear(); G[i].push_back(0); } memset(pre,0,sizeof(pre)); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); G[a[i]].push_back(i); } buildtree(1,1,n); if(k==1){ printf("%d ",n); continue; } int ans=0; for (int i=1;i<=n;i++){ int x=a[i]; int p=++pre[a[i]]; update(1,i,i,c-1); if(G[a[i]][p-1]+1<=G[a[i]][p]-1) update(1,G[a[i]][p-1]+1,G[a[i]][p]-1,-1); if(p>=k) update(1,G[a[i]][p-k]+1,G[a[i]][p-k+1],1); int pos=query(1); if(pos!=-1){ ans=max(ans,i-pos+1); } } printf("%d ",ans); } return 0; }