题目:点击此处

题意:给你n个数,q个询问,问每个区间的数最少需要几步可以删除完

删除的是一个等差序列

由于第一次删除之后,剩下的数字随机排列,所以,只要第一次删除可以把一种数字全部删除,剩下的步数就是数字种类数

总步数即为  总的种类数

 如果一次删不完一种数,那么答案就是总的种类数+1

判断是否是等差序列需要预处理  两个数组  fl[N],fr[N];

fl[i]表示i位置往左第一个构不成等差序列的位置

fr[i]同理;

 

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const int N=100005; 
struct node
{
    int x,y,p;
}q[N];
bool cmp(node a,node b)
{
    if (a.x/block!=b.x/block) 
        return  a.x/block<b.x/block;
    return a.y<b.y;
}
int aa[N];
int bak[N];
int pre[N];
int last[N];
int fl[N],fr[N];
int cnt[N];
int dengcha=0;
int kind=0;
int ans[N];
int L,R,block=sqrt(N);
void add1(int x)
{
    if(cnt[aa[x]]==0)
    {
        dengcha++;
        kind++;
    }
    else
    {
        if(fr[x]<=R&&fr[bak[x]]>R) dengcha--;
    }
    cnt[aa[x]]++;
}
void remov1e(int x)
{
    if(cnt[aa[x]]==1)
    {
        dengcha--;
        kind--;
    }
    else
    {
        if(fr[x]<=R&&fr[bak[x]]>R) dengcha++;
    }
    cnt[aa[x]]--;
}
void add2(int x,int l)
{
    if(cnt[aa[x]]==0)
    {
        dengcha++;
        kind++;
    }
    else
    {
        if(fl[x]>=l&&fl[pre[x]]<l) dengcha--;
    }
    cnt[aa[x]]++;
}
void remov2e(int x,int l)
{
    if(cnt[aa[x]]==1)
    {
        dengcha--;
        kind--;
    }
    else
    {
        if(fl[x]>=l&&fl[pre[x]]<l) dengcha++;
    }
    cnt[aa[x]]--;
}
void query(int x,int y,int flag)
{
    if (flag)
    {
        while(L>=x)
        {
            add1(L-1);
            L--;
        }
        while(L<x)
        {
            remov1e(L);
            L++;
        }
        while(R>y)
        {
            remov2e(R,x);
            R--;
        }
        while(R<y)
        {
            add2(R+1,x);
            R++;
        }
    }
    else
    {
        for (int i=x;i<=y;i++)
        {
            if(cnt[aa[i]]==0)
            {
                dengcha++;
                kind++;
            }
            else
            {
                if (fl[i]>=x&&fl[pre[i]]<x) dengcha--;//fl[i]>=x   指 i位置往左第一个构不成等差序列的位置在区间内, fl[pre[i]]<x 指 pre[i]位置往左第一个构不成等差序列的位置不在区间内,(防止重复计算)
            }
            cnt[aa[i]]++;
        }
        L=x,R=y;
    } 
}
void init()
{
    int i; 
    kind = 0;
    for (i=1; i<=m; i++)            //预处理
    {
        scanf("%d",&aa[i]);
        pre[i]=last[aa[i]];
        last[aa[i]]=i;
        if (pre[pre[i]]-pre[i]==pre[i]-i||pre[i]==0)
            fl[i]=fl[pre[i]];
        else fl[i]=pre[pre[i]];
    }
    fill(last,m+last,m+1);
    for (i=m; i>=1; i--)
    {
        bak[i]=last[aa[i]];
        last[aa[i]]=i;
        if (bak[bak[i]]-bak[i]==bak[i]-i||bak[i]==m+1)
            fr[i]=fr[bak[i]];
        else fr[i]=bak[bak[i]];
    }
}
int main()
{ 
    int m,i,j,qq,;
    cin>>m;
    init(); 
    scanf("%d",&qq);
    
    for (i=0;i<qq; i++)
    {
        scanf("%d%d",&q[i].x,&q[i].y);
        q[i].l=q[i].x/block_size;
        q[i].p=i;
    }
    sort(q,q+qq,cmp); 
    for (i=0;i<qq;i++)
    {
        query(q[i].x,q[i].y, i);
        ans[q[i].p]=kind+1;
        if (dengcha>0) 
            ans[q[i].p]--;
    } 
    for (i=0;i<qq;i++) 
        printf("%d\n",ans[i]);

    return 0;

}