1 条题解
-
0
自动搬运
来自洛谷,原作者为

bzy369258147
**搬运于
2025-08-24 22:10:14,当前版本为作者最后更新于2019-06-25 19:48:46,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
简述题意:
给定一个排列,多次询问,求一个区间 有多少个子区间的值都在区间 内。
算法1:
对于每个询问暴力枚举子区间,然后暴力检测是否满足条件,时间复杂度 。
用ST表预处理, 查询区间最值可以做到 。
期望得分:
算法2:
我们发现查询一个区间时,其中每个满足所有元素都在 内的 极长子区间 的贡献为 , 其中 为该子区间的长度。
于是对于每次询问时扫描出所有极长子区间即可做到 。
期望得分: ~
(虽然构造数据卡了,但还是被一位小常数玩家卡过去了第一档分)
算法3:
很容易想到要使用数据结构维护,于是我们想到了莫队,但是 值域 一直在变,似乎很难维护,所以我们选择转变思路。
由于题目给的序列时一个排列,所以我们考虑在值域上莫队,每次移动只会改变一个位置是否有效。然后考虑维护答案,很显然可以线段树。每个节点维护一下 左、右端开始的极长有效区间长度,区间答案,与区间是否全部有效即可。
时间复杂度
期望得分:
算法4:
考虑另一种 的做法,每次询问扫描值域,判断值域内每个值是否在区间内,在就更新答案。更新答案时需要用链表维护一下每个极大有效区间。
期望的分
算法5:
发现时间复杂度的瓶颈在于查询时需要线段树,考虑优化。
所以我们对序列分块,结合算法四的方法,每个块内单独维护一个链表,和区间的答案,由于维护的信息难以撤销,所以我们选择回滚莫队维护值域,区间长度小于等于 的使用算法4暴力,大于的部分每次 查询,每次莫队移动时维护所在块的链表,回滚时使用时间戳回溯。
总体时间复杂度 ,代码量4k左右。
期望得分:
总体来说这是一道简单的题,解法自然,码量适中,思维难度适中,考察了线段树、莫队、分块、链表等多种初等数据结构,是一道不折不扣的小清新数据结构好题。
附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
- 上传者