1 条题解

  • 0
    @ 2025-8-24 22:10:14

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar bzy369258147
    **

    搬运于2025-08-24 22:10:14,当前版本为作者最后更新于2019-06-25 19:48:46,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    简述题意:
    给定一个排列,多次询问,求一个区间 [l,r][l,r] 有多少个子区间的值都在区间 [x,y][x,y] 内。


    算法1:

    对于每个询问暴力枚举子区间,然后暴力检测是否满足条件,时间复杂度 O(qn3)O(qn^3)

    用ST表预处理, O(1)O(1)查询区间最值可以做到 O(qn2+nlogn)O(qn^2+nlogn)

    期望得分: 00

    算法2:

    我们发现查询一个区间时,其中每个满足所有元素都在 [x,y][x,y] 内的 极长子区间 的贡献为 t(t+1)2\frac{t(t+1)}{2}, 其中 tt 为该子区间的长度。

    于是对于每次询问时扫描出所有极长子区间即可做到 O(qn)O(qn)

    期望得分: 00 ~ 3434

    (虽然构造数据卡了,但还是被一位小常数玩家卡过去了第一档分)

    算法3:

    很容易想到要使用数据结构维护,于是我们想到了莫队,但是 值域[x,y][x,y] 一直在变,似乎很难维护,所以我们选择转变思路。

    由于题目给的序列时一个排列,所以我们考虑在值域上莫队,每次移动只会改变一个位置是否有效。然后考虑维护答案,很显然可以线段树。每个节点维护一下 左、右端开始的极长有效区间长度,区间答案,与区间是否全部有效即可。

    时间复杂度 O(nq logn)O(n\sqrt{q}\ logn)

    期望得分: 3434

    算法4:

    考虑另一种 O(qn)O(qn)的做法,每次询问扫描值域,判断值域内每个值是否在区间内,在就更新答案。更新答案时需要用链表维护一下每个极大有效区间。

    期望的分 00

    算法5:

    发现时间复杂度的瓶颈在于查询时需要线段树,考虑优化。

    所以我们对序列分块,结合算法四的方法,每个块内单独维护一个链表,和区间的答案,由于维护的信息难以撤销,所以我们选择回滚莫队维护值域,区间长度小于等于 2n2\sqrt{n}的使用算法4暴力,大于的部分每次 O(n)O(\sqrt{n})查询,每次莫队移动时O(1)O(1)维护所在块的链表,回滚时使用时间戳O(1)O(1)回溯。

    总体时间复杂度 O(nn)O(n\sqrt{n}),代码量4k左右。

    期望得分: 100100

    总体来说这是一道简单的题,解法自然,码量适中,思维难度适中,考察了线段树、莫队、分块、链表等多种初等数据结构,是一道不折不扣的小清新数据结构好题。

    附std:

    // 防抄袭片段已混入
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef unsigned char LL;
    
    LL que_range( int x ) { return 1ll * x * (x + 1) / 2; }
    
    template<int _size>
    struct stamp{
        //int A[ _size ];
        //int B[ _size ];
        //int T[ _size ];
        //int cnt = 1;
        //bool bind = false;
        
        //void Roll() { cnt ++; }
        //void Bind() { bind = true; Roll(); }
        //void Unte() { bind = false; }
        
        //void Set0() { memset( B, 0, sizeof(B) ); Roll(); }
        
        int& operator []( int index ) {
            if( bind ) {
                if( T[index] ^ cnt ) T[index] = cnt, A[index] = B[index];
                return A[index];
            } else return B[ index ];	
        }
    };
    
    int block = 10;
    int belong[200005];
    int beg[405];
    
    struct que{
        int l, r, x, y, id;	
        que() {}
        que( int _id ) { cin >> l >> r >> x >> y; id = _id; }
        bool operator <( que& from ) const
          { return belong[x] == belong[ from.x ] ? y < from.y : x < from.x; }
    };
    
    int n, q; 
    vector<que> Q;
    
    int c [200005];
    int uc[200005];
    
    stamp<200005> pre;
    stamp<200005> nxt;
    stamp<405> mid;
    
    int bf1( que& x ) { 
        int ans = 0, lst = 0;
        for( int i = x.l; i <= x.r; i ++ ) {
            if( c[i] <= x.y and c[i] >= x.x ) lst ++;
            else lst = 0;
            ans += lst;
        }
        return ans;
    }
    
    int bf2( que& x ) {
        int ans = 0;
        for(int i = x.x;i <= x.y;i ++) {
            int p = uc[i];
            if( p < x.l or p > x.r ) continue;
            ans -= que_range( p - pre[p - 1] );
            ans -= que_range( nxt[p + 1] - p );
            nxt[ pre[p - 1] ] = nxt[p + 1];
            pre[ nxt[p + 1] ] = pre[p - 1];
            ans += que_range( nxt[p + 1] - pre[p - 1] + 1 );
        }
        pre.Roll(); nxt.Roll();
        return ans;
    }
    
    void updata( int x ) {
        int p = uc[x], b = belong[p];
        if( p ^ beg[b] ) {
            if( pre[p - 1] != beg[b] ) mid[b] -= que_range( p - pre[p - 1] );
            if( p != beg[b + 1] - 1 )nxt[ pre[p - 1] ] = nxt[p + 1];
            else nxt[p] = p, pre[p] = pre[p - 1], nxt[ pre[p - 1] ] = p;
        }
        if( p ^ beg[b + 1] - 1 ) {
            if( nxt[p + 1] != beg[b + 1] - 1 ) mid[b] -= que_range( nxt[p + 1] - p );
            if( p != beg[b] ) pre[ nxt[p + 1] ] = pre[p - 1];
            else pre[p] = p, nxt[p] = nxt[p + 1], pre[ nxt[p + 1] ] = p;
        }
        if( p != beg[b] and p != beg[b + 1] - 1 and pre[p - 1] != beg[b] and nxt[p + 1] != beg[b + 1] - 1 ) 
            mid[b] += que_range( nxt[p + 1] - pre[p - 1] + 1 );
    }
    
    LL ans[200005];
    
    int main(){
        cin >> n >> q; 
        
        for(int i = 1;i <= n;i ++) {
            cin >> c[i]; uc[ c[i] ] = i;
            belong[i] = i / block + 1;
            if( belong[i] > belong[i - 1] ) beg[ belong[i] ] = i;
        }
        if( beg[ belong[n] ] == n ) belong[n] --;
        beg[ belong[n] + 1 ] = n + 1; belong[ n + 1 ] = belong[n] + 1;
        
        for(int i = 0;i <= n + 1;i ++) pre[i] = i + 1, nxt[i] = i - 1;
        nxt.Bind(); pre.Bind(); mid.Bind();
        
        for(int i = 1;i <= q;i ++) {
            que x = que(i);
            if     ( x.r - x.l <= block * 2 ) ans[i] = bf1( x );
            else if( x.y - x.x <= block * 2 ) ans[i] = bf2( x ); 
            else Q.push_back( x );
        }
        sort( Q.begin(), Q.end() );
        int pt = 0;
        for(int i = 1;i < belong[n];i ++) {
            int r = beg[i + 1] - 1;
            
            nxt.Unte(); pre.Unte(); mid.Unte();
            for(int j = 0;j <= n + 1;j ++) pre[j] = j + 1, nxt[j] = j - 1; mid.Set0();
            
            while( pt < Q.size() and belong[ Q[pt].x ]  == i ) {
                auto &P = Q[pt];
                
                nxt.Unte(); pre.Unte(); mid.Unte();
                while( r < P.y ) updata( ++ r );
                
                nxt.Bind(); pre.Bind(); mid.Bind();
                for( int j = P.x; j < beg[i + 1]; j ++ ) updata( j );
                
                long long Ans = 0, lst = 0; 
                int bl = belong[ P.l - 1 ] + 1;
                int br = belong[ P.r + 1 ] - 1;
                
                for( int j = P.l; belong[j] < bl; j ++ ) {
                    if( c[j] >= P.x and c[j] <= P.y ) lst ++;
                    else Ans += que_range( lst ), lst = 0;
                }
                
                for( int j = bl; j <= br; j ++ ) {
                    if( nxt[ beg[j] ] == beg[j + 1] - 1 ) lst += beg[j + 1] - beg[j];
                    else {
                        lst += nxt[ beg[j] ] - beg[j] + 1;
                        Ans += que_range(lst); Ans += mid[j];
                        lst = beg[j + 1] - pre[ beg[j + 1] - 1 ];
                    }
                }
                
                for( int j = beg[br + 1]; j <= P.r; j ++ ) {
                    if( c[j] >= P.x and c[j] <= P.y ) lst ++;
                    else Ans += que_range( lst ), lst = 0;
                }
                
                Ans += que_range( lst );
                ans[ P.id ] = Ans;
                
                nxt.Roll(); pre.Roll(); mid.Roll();
                pt ++;
            }
        }
        for(int i = 1;i <= q;i ++) cout << ans[i] << "\n";
        return 0;
    }
    
    • 1

    信息

    ID
    4308
    时间
    3000~7000ms
    内存
    125MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者