跳转至

P5070 即便看不到未来

题面

原题链接 click

题解

前言:我写完代码发现读错题了,白花 \(2\mathrm h\)

先理解一下题目意思,就是把一段区间排序去重后统计各个长度的极长连续段数量。
经典的,考虑移动右端点 \(r\),处理各个 \(l\) 的答案。
我们发现,新加入 \(a_r\) 时只用统计 \(a_r\) 附近的若干个值,记 \(bst_k\)\(k\)\(a_1,\cdots,a_{r-1}\) 中最后一次出现位置。
我们取出 \(a_r-11,a_r-10,\cdots,a_r+11\)\(23\) 个数的最后出现位置并排序,然后处理合并即可,开 \(10\) 个树状数组不难实现。
复杂度 \(O(nk\log n)\),其中 \(k=10\),由于树状数组常数较小,可以通过。

Code
#include<bits/stdc++.h>
using namespace std;
int a[1000005];
int n,q;
struct qry{
    int l,r,id;
};
qry s[1000005];
bool cmp1(qry x,qry y){
    return x.r<y.r;
}
int ans[1000005][12];
int bst[1000005];
int h[25],m;
bool cmp2(int u,int v){
    return bst[u]>bst[v];
}
int c[12][1000005];
inline void add(const int k,int u){
    if(k>10||k==0) return;
    // cerr<<"add "<<k<<' '<<u<<'\n';
    while(u<=n){
        c[k][u]++; c[k][u]%=10;
        // cerr<<"c["<<k<<"]["<<u<<"]="<<c[k][u]<<'\n';
        u+=u&-u;
    }
}
inline void del(const int k,int u){
    if(k>10||k==0) return;
    // cerr<<"del "<<k<<' '<<u<<'\n';
    while(u<=n){
        c[k][u]+=9; c[k][u]%=10;
        // cerr<<"c["<<k<<"]["<<u<<"]="<<c[k][u]<<'\n';
        u+=u&-u;
    }
}
inline int sum(const int k,int u){
    int v=u;
    int res=0;
    while(u){
        // cerr<<"c["<<k<<"]["<<u<<"]="<<c[k][u]<<'\n';
        res+=c[k][u]; u&=u-1;
    }
    // cerr<<"qry "<<k<<" "<<v<<'=';
    // cerr<<res%10<<'\n';
    return res%10;
}
int mem[30],*f=mem+15;
int main(){
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n>>q; a[0]=a[n+1]=-1;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=q;i++){
        cin>>s[i].l>>s[i].r; s[i].id=i;
    }
    sort(s+1,s+1+q,cmp1);
    int ps=1;
    for(int i=1;i<=n;i++){
        // cerr<<"i="<<i<<'\n';
        m=0;
        for(int j=max(1,a[i]-11);j<=min(1000000,a[i]+11);j++){
            h[++m]=j;
        }
        h[m+1]=0;
        sort(h+1,h+1+m,cmp2);
        memset(mem,0,sizeof(mem));
        add(1,bst[h[1]]+1); del(1,i+1);
        int pos1=0,pos2=0;
        for(int j=1;j<=m;j++){
            if(h[j]==a[i]) break;
            if(bst[h[j]]==0) break;
            f[h[j]-a[i]]=1;
            while(f[-pos1-1]==1) pos1++;
            while(f[pos2+1]==1) pos2++;
            del(pos1,bst[h[j+1]]+1);
            add(pos1,bst[h[j]]+1);

            del(pos2,bst[h[j+1]]+1);
            add(pos2,bst[h[j]]+1);

            add(pos1+pos2+1,bst[h[j+1]]+1);
            del(pos1+pos2+1,bst[h[j]]+1);
            // cerr<<'\n';
        }
        // cerr<<'\n';
        while(s[ps].r==i){
            ans[s[ps].id][1]=sum(1,s[ps].l);
            ans[s[ps].id][2]=sum(2,s[ps].l);
            ans[s[ps].id][3]=sum(3,s[ps].l);
            ans[s[ps].id][4]=sum(4,s[ps].l);
            ans[s[ps].id][5]=sum(5,s[ps].l);
            ans[s[ps].id][6]=sum(6,s[ps].l);
            ans[s[ps].id][7]=sum(7,s[ps].l);
            ans[s[ps].id][8]=sum(8,s[ps].l);
            ans[s[ps].id][9]=sum(9,s[ps].l);
            ans[s[ps].id][10]=sum(10,s[ps].l);
            ps++;
        }
        bst[a[i]]=i;
    }
    for(int i=1;i<=q;i++){
        putchar(48+ans[i][1]);
        putchar(48+ans[i][2]);
        putchar(48+ans[i][3]);
        putchar(48+ans[i][4]);
        putchar(48+ans[i][5]);
        putchar(48+ans[i][6]);
        putchar(48+ans[i][7]);
        putchar(48+ans[i][8]);
        putchar(48+ans[i][9]);
        putchar(48+ans[i][10]);
        putchar(10);
    }
    return 0;
}