题意:给出 n m x y z,表示有一个含有 n 个元素的数组,有 m 次操作,这 m 次操作要通过一个函数的结果得出的
使用给出的 x y z 可以把 f函数 1 到 3 * m 的值先算出来,然后m次操作里使用 f 函数的值去算出 l r v
操作就是对数组上 [ l , r ] 的区间做更新,如果 v > a[ i ] 那么就把 a [ i ] 的值更新为 v
最后求数组里的数 * i 后的异或和
思路:反向地使用 ST表,对区间进行更新的时候,直接更新 ST 表最上层的相互率最大且相互不超出的两个区间
比如现在更新的区间 是 [ 5 , 11 ] 这个区间长度为 7 ,那么要更新的两个区间就是 [ 5 , 9 ] 和 [ 7 , 11 ] 因为小于 7 的最大的2的此方数 为 4,所以两个子区间长度要为 4
这样把所有操作都做完之后,从最上层开始往下更新,把值往下更新,最后更新到最底层的时候数组每个位置的值就出来了
#include<bits/stdc++.h>
using namespace std;
#define ui unsigned int
#define ll long long
#define mem(a,x) memset(a,x,sizeof(a))
const int maxn = 1e5 + 5;
const int maxm = (5e6 + 5) * 3;
const int mod = 1 << 30;
ui x,y,z,st[maxn][20],f[maxm];
int logs[maxn];
ui func(){
x = x ^ (x << 11);
x = x ^ (x >> 4);
x = x ^ (x << 5);
x = x ^ (x >> 14);
ui w = x ^ (y ^ z);
x = y;
y = z;
z = w;
return z;
}
void init(){
logs[0] = -1;
for(int i = 1;i < maxn;i++){
logs[i] = logs[i >> 1] + 1;
}
}
int main(){
int T,n,m;
init();
scanf("%d",&T);
while(T--){
scanf("%d %d %u %u %u",&n,&m,&x,&y,&z);
mem(st,0);
for(int i = 1;i <= 3 * m;i++){
f[i] = func();
}
int maxbit = 0;
for(int i = 1;i <= m;i++){
int l = min((f[3 * i - 2] % n) + 1,(f[3 * i - 1] % n) + 1);
int r = max((f[3 * i - 2] % n) + 1,(f[3 * i - 1] % n) + 1);
ui v = f[3 * i] % mod;
int k = logs[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);
maxbit = max(maxbit,k);
}
for(int i = maxbit;i >= 1;i--){
int k = 1 << i;
for(int j = 1;j <= n;j++){
if(j + k - 1 > n)
break;
st[j][i - 1] = max(st[j][i - 1],st[j][i]);
st[j + (k >> 1)][i - 1] = max(st[j + (k >> 1)][i - 1],st[j][i]);
}
}
ll ans = 0;
for(int i = 1;i <= n;i++){
ans ^= 1ll * st[i][0] * i;
}
printf("%lld\n",ans);
}
return 0;
}