Luogu

分析

把询问离线,从左往右加入每个数并维护以这个数为右端点时每个左端点的答案。

假设当前加入了 $x$,那么它显然不会更新 $a_x$ 上一次出现位置之前的左端点的答案(因为这些区间排序去重后根本没有变化),而且只会和 $[x-11,x+11]$ 的数产生贡献(因为只需要统计 $\leq 10$ 的长度)。而插入 $x$ 后极长值域连续段可能会有以下变化

  • 从 $[a,x-1]$ 变成了 $[a,x]$;
  • 从 $[x+1,b]$ 变成了 $[x,b]$;
  • 从 $[a,x-1]\cup[x+1,b]$ 变成了 $[a,b]$。

我们把所有 $[x-11,x+11]$ 内的数在已经加入的数中的最后位置从大到小排序并依次插入,显然当前插入的数会影响左端点在它到下一个数的位置 $-1$ 的答案。具体的,这些位置原来存在的长度为 $L,R$ 的极长值域连续段变成了一个长度为 $L+R+1$ 的极长值域连续段。开 $10$ 个树状数组维护每个左端点对应的每种长度的个数即可。

可以参考代码理解。

代码

// ====================================
//   author: M_sea
//   website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#define file(x) freopen(#x".in","r",stdin); freopen(#x".out","w",stdout)
using namespace std;
typedef long long ll;

int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=1000000+10;

int n,m,a[N],lst[N],vis[N],ans[N][15];
struct query { int l,id; };
vector<query> q[N];
struct num { int p,w; };
bool operator <(num x,num y) { return x.p>y.p; }
vector<num> v;
vector<int> del;

struct BIT {
    int c[N];
    void add(int x,int y) { for (;x<=n;x+=x&-x) c[x]+=y; }
    int sum(int x) { int s=0; for (;x;x-=x&-x) s+=c[x]; return s; }
} t[11];

int main() {
    n=read(),m=read();
    for (int i=1;i<=n;++i) a[i]=read();
    for (int i=1;i<=m;++i) {
        int l=read(),r=read();
        q[r].emplace_back((query){l,i});
    }
    for (int i=1;i<=n;++i) {
        v.clear(),del.clear();
        for (int j=max(1,a[i]-11);j<=a[i]+11;++j)
            if (lst[j]>lst[a[i]]) v.emplace_back((num){lst[j],j});
        v.emplace_back((num){lst[a[i]],0}),v.emplace_back((num){i,a[i]});
        sort(v.begin(),v.end());
        for (int j=0,L=0,R=0;j<v.size()-1;++j) {
            vis[v[j].w]=1; del.emplace_back(v[j].w);
            while (vis[a[i]-L-1]) ++L;
            while (vis[a[i]+R+1]) ++R;
            int U=L+R+1;
            if (1<=L&&L<=10) t[L].add(v[j+1].p+1,-1),t[L].add(v[j].p+1,1);
            if (1<=R&&R<=10) t[R].add(v[j+1].p+1,-1),t[R].add(v[j].p+1,1);
            if (1<=U&&U<=10) t[U].add(v[j+1].p+1,1),t[U].add(v[j].p+1,-1);
        }
        for (int j:del) vis[j]=0;
        for (auto j:q[i])
            for (int k=1;k<=10;++k)
                ans[j.id][k]=t[k].sum(j.l);
        lst[a[i]]=i;
    }
    for (int i=1;i<=m;++i) {
        for (int j=1;j<=10;++j)
            putchar(ans[i][j]%10+'0');
        putchar('\n');
    }
    return 0;
}
最后修改:2020 年 07 月 02 日 08 : 18 PM