2018 Multi-University Training Contest 5 - Glad You Came
st表
倒着用st表。
在rmq的时候,st表可以递推出区间的最值,这些最值是由若干个小区间组成,最小的区间就是这个数本身,也就是st[i][0]。
对于这道题,我们可以倒着用st表,在每次操作的时候,我们先把[l...r]这个区间用st表覆盖(相当于rmq的查询)。
然后再从最大的区间依次向下递推,去更新小区间。
因为正在递推小区间是可以组合成所有大区间的,因此反着推大区间也可以覆盖所有小区间。
最后st[i][0]就是m次操作后每个数本身,异或起来就是答案。
这里如果长度超过了最大区间长度,那么st表的值就是0,因此不用担心越界。。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define full(a, b) memset(a, b, sizeof a)
#define FAST_IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
using namespace std;
typedef long long ll;
typedef unsigned int ui;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
int X = 0, w = 0; char ch = 0;
while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
return w ? -X : X;
}
inline int gcd(int a, int b){ return b ? gcd(b, a % b) : a; }
inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
template<typename T>
inline T max(T x, T y, T z){ return max(max(x, y), z); }
template<typename T>
inline T min(T x, T y, T z){ return min(min(x, y), z); }
template<typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){
A ans = 1;
for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
return ans;
}
const int N = 200005;
const ui MOD = (1 << 30);
int n, m , _, lb[N];
ui x, y, z, w, st[N][21];
ui rng61(){
x ^= (x << 11);
x ^= (x >> 4);
x ^= (x << 5);
x ^= (x >> 14);
w = x ^ (y ^ z);
x = y, y = z, z = w;
return z;
}
int main(){
lb[0] = -1; for(int i = 1; i <= N; i ++) lb[i] = lb[i >> 1] + 1;
for(_ = read(); _; _ --){
//full(st, 0);
n = read(), m = read(), x = read(), y = read(), z = read();
for(int i = 1; i <= m; i ++){
ui f1 = rng61(), f2 = rng61(), f3 = rng61();
ui l = min((f1 % n) + 1, (f2 % n) + 1);
ui r = max((f1 % n) + 1, (f2 % n) + 1);
ui v = f3 % MOD;
int k = lb[r - l + 1];
st[l][k] = max(st[l][k], v);
st[r - (1 << k) + 1][k] = max(st[r - (1 << k) + 1][k], v);
}
for(int i = lb[n]; i >= 1; i --){
for(int j = 1; j <= n; j ++){
st[j][i - 1] = max(st[j][i - 1], st[j][i]);
st[j + (1 << (i - 1))][i - 1] = max(st[j + (1 << (i - 1))][i - 1], st[j][i]);
st[j][i] = 0;
}
}
ll ans = 0;
for(int i = 1; i <= n; i ++){
ans ^= (1LL * st[i][0] * i);
st[i][0] = 0;
}
printf("%lld\n", ans);
}
return 0;
}