题意

线段树
这个题可以先排序,从左到右做,每次更新这个颜色最后一次出现的位置,放入线段树。如果所有颜色都出现过,就去线段树中查询所有颜色最后一次出现时间的最小值。每次更新当前位置与这个最小值之差的最小值作为答案,时间复杂度为O(N(log n+log k))。线段树长度只用开k即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls (k<<1)
#define rs (k<<1|1)
#define mid (l+r>>1)
#define Mid (t[k].l+t[k].r>>1)
int Min(int x,int y)
{
    return x<y?x:y;
}
struct node
{
    int l,r,v;
    node(int l,int r)
    {
        this->l=l;
        this->r=r;
        v=-1;
    }
    node()
    {
        v=-1;
    }
}t[500];
void build(int k,int l,int r)
{
    t[k]=node(l,r);
    if(l==r)
        return;
    build(ls,l,mid);
    build(rs,mid+1,r);
}
void change(int k,int p,int x)
{
    if(t[k].l==t[k].r)
    {
        t[k].v=x;
        return;
    }
    if(p<=Mid)
        change(ls,p,x);
    else
        change(rs,p,x);
    t[k].v=Min(t[ls].v,t[rs].v);
    return;
}
int ask(int k,int l,int r)
{
    if(t[k].l==l&&t[k].r==r)
        return t[k].v;
    if(r<=Mid)
        return ask(ls,l,r);
    else if(l>Mid)
        return ask(rs,l,r);
    else
        return Min(ask(ls,l,Mid),ask(rs,Mid+1,r));
}

struct ball
{
    int c,p;
    friend bool operator <(ball a,ball b)
    {
        return a.p<b.p;
    }
}a[1000010];
int cnt=0;
int main()
{
    int n,k,t,u;
    scanf("%d%d",&n,&k);
    build(1,1,k);
    for(int i=1;i<=k;i++)
    {
        scanf("%d",&t);
        for(int j=1;j<=t;j++)
        {
            scanf("%d",&u);
            a[++cnt].c=i;
            a[cnt].p=u;
        }
    }
    std::sort(a+1,a+1+n);
    int ans=0x7fffffff;
    for(int i=1;i<=n;i++)
    {
        change(1,a[i].c,a[i].p);
        int tmp=ask(1,1,k);//更新最晚值
        if(tmp==-1)//为-1说明还有颜色没找到
            continue;
        ans=ans<(a[i].p-tmp)?ans:(a[i].p-tmp);
    }
    printf("%d\n",ans);
    return 0;
}