多校2 Longest Subarray 线段树

  题意:给定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;
}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/11241725.html