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;
}

猜你喜欢

转载自www.cnblogs.com/onionQAQ/p/10933210.html