LOJ10042 收集雪花

时间:2024-01-01 23:17:40

题意

不同的雪花往往有不同的形状。在北方的同学想将雪花收集起来,作为礼物送给在南方的同学们。一共有 n 个时刻,给出每个时刻下落雪花的形状,用不同的整数表示不同的形状。在收集的过程中,同学们不希望有重复的雪花。你可以从任意 a 时刻开始,在 b 时刻停止。 a 到 b 时刻中间的雪花也都将被收集。他们希望收集的雪花最多。

\(1≤n≤10^6,0≤x_i≤10^9\)

分析

参照jklover的题解。

首先需要离散化或hash,将值域控制在1e6的级别.

然后,若直接上主席树,每次二分答案,枚举左端点,是O(nlog2n)的,十分弱智巨.

优秀的做法是Two Pointers.维护两个指针l,r,不断往后跳,同时用类似于莫队的方法维护当前区间内颜色种类数目.合法时更新答案.

这样每个指针最多跳n次,一共跳2n次,相当优秀.

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
    rg T data=0;
    rg int w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data*w;
}
template<class T>il T read(rg T&x)
{
    return x=read<T>();
}
typedef long long ll;
using namespace std;

co int N=1e6+1;
int n,x[N],y[N],cnt;
int t[N],cols;

void ins(int p)
{
    if(++t[x[p]]==1)
        ++cols;
}

void del(int p)
{
    if(--t[x[p]]==0)
        --cols;
}

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    read(n);
    for(int i=1;i<=n;++i)
        y[i]=read(x[i]);
    sort(y+1,y+n+1);
    cnt=unique(y+1,y+n+1)-(y+1);
    for(int i=1;i<=n;++i)
        x[i]=lower_bound(y+1,y+cnt+1,x[i])-y;
    int l=1,r=1,ans=0;
    for(;r<=n;++r)
    {
        ins(r);
        while(l<=r&&cols!=r-l+1)
            del(l++);
        if(cols==r-l+1)
            ans=max(ans,r-l+1);
    }
    printf("%d\n",ans);
    return 0;
}