回坑做ynoi,然后发现自己的脑子就是一团浆糊
首先仔细阅读题目,我们发现由于是对于询问的区间先排序后在讨论(刚开始看错了以为不可做题),所以显然可以离线一波
把询问按右端点从小到大排,每次加入右边的位置然后询问左端点的答案
考虑加入一个数之后的贡献,容易发现有四种:
- 这个数不和之前的任何数相邻,单独加上(1)的贡献
- 这个数在一边和之前的数相邻,要把原来的贡献减(1)然后加上现在(1)的贡献
- 这个数在两边都和其他数相邻,把两边的贡献都减了然后加上这一段长的
- 这个数以前出现过了,那么只处理从上次出现位置到当前位置的贡献变化
然后我们容易把贡献的影响归为一类,即对于加入的(a_i),若((a_i-fr,a_i))和((a_i,a_i+bk))均出现过
那么删除((a_i-fr,a_i))和((a_i,a_i+bk))的贡献然后加入((a_i-fr,a_i+bk))的贡献即可
然后我们发现这个东西和答案都不大好维护的样子,那不是GG
细细一看题目原来查询的区间长度都是(le 10)的,那么就意味着我们每次只需要暴力扫一遍((a_i-11,a_i))和((a_i,a_i+11))即可进行更新
同理我们也可以直接开(10)个树状数组来维护贡献,具体地直接记录后缀和即可
注意更新贡献的时候要从后往前做才能防止重漏
具体实现详见代码
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<iostream>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=1e6+5;
struct ques
{
int l,r,id;
friend inline bool operator < (const ques& A,const ques& B)
{
return A.r<B.r;
}
}q[N];
struct data
{
int x,y;
friend inline bool operator < (const data& A,const data& B)
{
return A.x>B.x;
}
}p[50];
int n,m,mx,tot,a[N],lst[N]; char ans[N][11];
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
char Fin[S],*A,*B;
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
#undef tc
}F;
class TreeArray
{
private:
int bit[N];
#define lowbit(x) (x&-x)
public:
inline void add(RI x,CI y)
{
for (;x;x-=lowbit(x)) bit[x]+=y;
}
inline int get(RI x,int y=0)
{
for (;x<=n;x+=lowbit(x)) y+=bit[x]; return y;
}
#undef lowbit
}BIT[11];
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),F.read(m),i=1;i<=n;++i) F.read(a[i]),mx=max(mx,a[i]);
for (i=1;i<=m;++i) F.read(q[i].l),F.read(q[i].r),q[i].id=i;
for (sort(q+1,q+m+1),tot=i=1;i<=n;++i)
{
RI cnt=0,j,fr=0,bk=0; for (j=max(1,a[i]-11);j<=min(mx,a[i]+11);++j)
if (lst[j]>lst[a[i]]) p[++cnt]=(data){lst[j],j}; p[++cnt]=(data){i,a[i]};
for (p[cnt+1].x=lst[a[i]],sort(p+1,p+cnt+1),j=1;j<=cnt;++j)
{
if (p[j].y<a[i]) while (fr<=10&&(a[i]-fr-1==p[j].y||lst[a[i]-fr-1]>p[j].x)) ++fr;
if (p[j].y>a[i]) while (bk<=10&&(a[i]+bk+1==p[j].y||lst[a[i]+bk+1]>p[j].x)) ++bk;
if (1<=fr&&fr<=10) BIT[fr].add(p[j].x,-1),BIT[fr].add(p[j+1].x,1);
if (1<=bk&&bk<=10) BIT[bk].add(p[j].x,-1),BIT[bk].add(p[j+1].x,1);
if (fr+bk+1<=10) BIT[fr+bk+1].add(p[j].x,1),BIT[fr+bk+1].add(p[j+1].x,-1);
}
lst[a[i]]=i; while (tot<=m&&q[tot].r==i)
{ for (j=1;j<=10;++j) ans[q[tot].id][j]=BIT[j].get(q[tot].l)%10+48; ++tot; }
}
for (i=1;i<=m;++i) puts(ans[i]+1); return 0;
}