[SCOI2016]美味

按位从高往低贪心,枚举到第i位,只需要判断这2^i长度的区间是否有菜,用主席树就可以了

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(4e6 + 10), SIZE(1e5);

IL ll Read(){
    char c = '%'; ll x = 0, z = 1;
    for(; c > '9' || c < '0'; c = getchar()) if(c == '-') z = -1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
    return x * z;
}

int n, m, cnt, rt[_], ls[_], rs[_], sz[_];

IL void Build(RG int &x, RG int l, RG int r){
    x = ++cnt;
    if(l == r) return;
    RG int mid = (l + r) >> 1;
    Build(ls[x], l, mid); Build(rs[x], mid + 1, r);
}

IL void Modify(RG int &x, RG int l, RG int r, RG int v){
    sz[++cnt] = sz[x]; ls[cnt] = ls[x]; rs[cnt] = rs[x]; ++sz[x = cnt];
    if(l == r) return;
    RG int mid = (l + r) >> 1;
    if(v <= mid) Modify(ls[x], l, mid, v);
    else Modify(rs[x], mid + 1, r, v);
}

IL int Query(RG int A, RG int B, RG int l, RG int r, RG int L, RG int R){
    if(L > R) return 0;
    if(L <= l && R >= r) return sz[B] - sz[A];
    RG int sum = 0, mid = (l + r) >> 1;
    if(L <= mid) sum = Query(ls[A], ls[B], l, mid, L, R);
    if(R > mid) sum += Query(rs[A], rs[B], mid + 1, r, L, R);
    return sum;
}

int main(RG int argc, RG char *argv[]){
    n = Read(); m = Read();
    Build(rt[0], 0, SIZE);
    for(RG int i = 1, a; i <= n; ++i) a = Read(), rt[i] = rt[i - 1], Modify(rt[i], 0, SIZE, a);
    for(RG int i = 1, b, x, l, r, ans = 0; i <= m; ++i){
        b = Read(); x = Read(); l = Read(); r = Read(); ans = 0;
        for(RG int j = 17, t, L, R; j >= 0; j--){
            if(b & (1 << j)) L = ans, R = ans + (1 << j) - 1, t = 0;
            else L = ans + (1 << j), R = ans + (1 << (j + 1)) - 1, t = 1;
            if(!Query(rt[r], rt[l - 1], 0, SIZE, max(0, L - x), min(R - x, SIZE))) t ^= 1;
            ans |= t << j;
        }
        printf("%d
", ans ^ b);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cjoieryl/p/8206338.html