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

yijan
我结束了!搬运于
2025-08-24 22:22:21,当前版本为作者最后更新于2020-06-09 10:26:37,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
考虑一次查询,比如查询 区间。
首先找出区间内最小值的位置,设为 。
考虑把询问的区间的子区间分成三种:
- 跨过了
- 左右端点都在
- 左右端点都在
考虑分别处理。对于第一种,明显贡献是 。
下面设 表示左端点在 内,右端点在 内的所有区间的最小值的和。
我们考虑怎么求 的值。我们把这个拆成:
也就是左右端点都在 减去左右都在 再减去左端点在 右端点在 的贡献。
怎么求 呢,考虑预处理出来。为了方便设 ,于是可以发现
再设 。考虑怎么递推出 。对于每个位置 ,设 为满足 的最小值,也就是说 小于 的所有值。于是
于是递推求出了 也就求出了 。
回到原来的问题,我们还需要求 。这个东西看起来求不了。但是,对于第二种询问,我们要求的是
由于 是 的最小值,这个东西直接等于 。因为左端点的选择是 中任意选择,且每个区间都一定是 后面更小,所以就是 的 倍了。
呢?倒过来(后缀变前缀)一样整一遍即可。
实现上,求 直接单调栈即可。复杂度瓶颈在 ST 表的 ,用转01 RMQ 后整 线性的 ST 表也可以做到 。
代码很好写+好调。。代码后面留了个 gen。
#include "iostream" #include "algorithm" #include "cstring" #include "cstdio" #include "cmath" #include "vector" #include "map" #include "set" #include "queue" using namespace std; #define MAXN 1000006 //#define int long long #define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i) #define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i) #define pii pair<int,int> #define fi first #define se second #define mp make_pair #define pb push_back #define eb emplace_back #define vi vector<int> #define all(x) (x).begin() , (x).end() #define mem( a ) memset( a , 0 , sizeof a ) typedef long long ll; int n , q; int A[MAXN] , p[19][MAXN] , L[MAXN] , R[MAXN] , lg[MAXN]; ll f[MAXN] , F[MAXN] , g[MAXN] , G[MAXN]; int stk[MAXN] , top; namespace gen{ typedef unsigned long long ull; ull s,a,b,c,lastans=0; void in( ) { cin >> s >> a >> b >> c; } ull rand(){ return s^=(a+b*lastans)%c; } }; void solve() { int typ; cin >> n >> q >> typ; lg[0] = -1; rep( i , 1 , n ) scanf("%d",&A[i]) , p[0][i] = i , lg[i] = lg[i >> 1] + 1; rep( i , 1 , 18 ) for( int j = 1 ; j + ( 1 << i ) - 1 <= n ; ++ j ) p[i][j] = ( A[p[i - 1][j]] < A[p[i - 1][j + ( 1 << i - 1 )]] ? p[i - 1][j] : p[i - 1][j + ( 1 << i - 1 )] ); rep( i , 1 , n ) { while( top && A[stk[top]] > A[i] ) R[stk[top]] = i , -- top; stk[++ top] = i; } while( top ) R[stk[top]] = n + 1 , -- top; per( i , n , 1 ) { while( top && A[stk[top]] > A[i] ) L[stk[top]] = i , -- top; stk[++ top] = i; } while( top ) L[stk[top]] = 0 , -- top; per( i , n , 1 ) F[i] = F[R[i]] + A[i] * 1ll * ( R[i] - i ) , f[i] = f[i + 1] + F[i]; rep( i , 1 , n ) G[i] = G[L[i]] + A[i] * 1ll * ( i - L[i] ) , g[i] = g[i - 1] + G[i]; int l , r , pos , len; unsigned long long re = 0 , res = 0; if( !typ ) { while( q-- ) { scanf("%d%d",&l,&r); len = lg[r - l + 1]; pos = ( A[p[len][l]] < A[p[len][r - ( 1 << len ) + 1]] ? p[len][l] : p[len][r - ( 1 << len ) + 1] ); res = f[l] - f[pos] - ( pos - l ) * F[pos] + g[r] - g[pos] - ( r - pos ) * G[pos] + ( pos - l + 1 ) * 1ll * ( r - pos + 1 ) * A[pos]; re ^= res; } } else { gen::in(); while( q-- ) { l = gen::rand() % n + 1 , r = gen::rand() % n + 1; if( l > r ) swap( l , r ); len = lg[r - l + 1]; pos = ( A[p[len][l]] < A[p[len][r - ( 1 << len ) + 1]] ? p[len][l] : p[len][r - ( 1 << len ) + 1] ); res = f[l] - f[pos] - ( pos - l ) * F[pos] + g[r] - g[pos] - ( r - pos ) * G[pos] + ( pos - l + 1 ) * 1ll * ( r - pos + 1 ) * A[pos]; gen::lastans = res; re ^= res; } } cout << re << endl; } signed main() { // int T;cin >> T;while( T-- ) solve(); solve(); } /* void solve() { srand( (long long) new char ); n = 10 , m = 10; cout << n << ' ' << m << endl; rep( i , 1 , n ) printf("%d ",rand() % 2000000000 - 1000000000 + 1); puts(""); rep( i , 1 , m ) { int l = rand() % n + 1 , r = rand() % n + 1; if( l > r ) swap( l , r ); printf("%d %d\n",l,r); } } */
- 1
信息
- ID
- 5639
- 时间
- 1000ms
- 内存
- 500MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者