线性基+线段树

线性基+线段树

XOR 计蒜客

t组数据,n个数的序列,q次查询,取l,r区间中的数,使得这些数异或后 或 (|)上k的最大值。

因为最后要 或 上 k,在二进制中,k为1的位置,最后结果也会是1,所以取数的时候,要a[i] & (~k),把一些位置的1消掉。再求最大异或。

举个例子:k = 8,a[] = {6(110), 10(1010)},如果直接求最大异或 | k,答案是12;如果进行a[i]&(~k)消掉一些1,答案是14;

用线段树维护。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
struct tree
{
    LL l, r;
    LL d[70];
}t[40010];
LL a[10010], k;
void built(LL l, LL r, LL x) {
    t[x].l = l, t[x].r = r;
    if(l == r) {
        memset(t[x].d, 0, sizeof(t[x].d));
        LL b = a[l] & (~k);
        for(LL i = 60; i >= 0; i--) {
            if(b & (1LL << i)) {
                if(t[x].d[i]) b ^= t[x].d[i];
                else {
                    t[x].d[i] = b;
                    break;
                }
            }
        }
        return ;
    }
    LL mid = (l + r) / 2;
    built(l, mid, x*2);
    built(mid + 1, r, x*2+1);
    for(LL j = 60; j >= 0; j--) {
        if(t[x*2].d[j]) {
            LL b = t[x*2].d[j];
            for(LL i = 60; i >= 0; i--) {
                if(b & (1LL << i)) {
                    if(t[x].d[i]) b ^= t[x].d[i];
                    else {
                        t[x].d[i] = b;
                        break;
                    }
                }
            }
        }
        if(t[x*2+1].d[j]) {
            LL b = t[x*2+1].d[j];
            for(LL i = 60; i >= 0; i--) {
                if(b & (1LL << i)) {
                    if(t[x].d[i]) b ^= t[x].d[i];
                    else {
                        t[x].d[i] = b;
                        break;
                    }
                }
            }
        }
    }
}
LL ans[70];
void ask(LL l, LL r, LL x) {
    if(l <= t[x].l && t[x].r <= r) {
        for(LL j = 60; j >= 0; j--) {
            LL b = t[x].d[j];
            if(b) {
                for(LL i = 60; i >= 0; i--) {
                    if(b & (1LL << i)) {
                        if(ans[i]) b ^= ans[i];
                        else {
                            ans[i] = b;
                            break;
                        }
                    }
                }
            }
        }
        return ;
    }
    LL mid = (t[x].l + t[x].r) / 2;
    if(l <= mid) ask(l, r, x*2);
    if(r > mid) ask(l, r, x*2+1);
}
int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        LL n, q;
        scanf("%lld %lld %lld", &n, &q, &k);
        for(LL i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
        }
        built(1, n, 1);
        while(q--) {
            LL l, r;
            scanf("%lld %lld", &l, &r);
            memset(ans, 0, sizeof(ans));
            ask(l, r, 1);
            LL sum = 0;
            for(LL i = 60; i >= 0; i--) {
                if((sum ^ ans[i]) > sum) sum ^= ans[i];
            }
            printf("%lld\n", sum | k);
        }
    }
    return 0;
}

Operation HDU 6579

t组数据,n个数的序列,m次操作,操作1:0 l r,询问[l,r]最大异或。操作2:1 x 在序列最后面加入x

看这个大佬的博客吧https://www.cnblogs.com/KirinSB/p/11248546.html

#include <cstdio>
#include <cstring>
int d[35], nd[1000010][35], mpos[1000010][35], pos[35];
void add(int x, int r) {
    int rr = r;
    for(int i = 31; i >= 0; i--) {
        if(x & (1 << i)) {
            if(d[i]) {
                if(pos[i] < r) {
                    int tmp = pos[i];
                    pos[i] = r;
                    r = tmp;
                    tmp = x;
                    x = d[i];
                    d[i] = tmp;
                }
                x ^= d[i];
            }
            else {
                d[i] = x;
                pos[i] = r;
                break;
            }
        }
    }
    for(int i = 31; i >= 0; i--) {
        nd[rr][i] = d[i];
        mpos[rr][i] = pos[i];
    }
}
int ask(int l, int r) {
    int ret = 0;
    for(int i = 31; i >= 0; i--) {
        if(mpos[r][i] >= l) {
            if((ret ^ nd[r][i]) > ret) ret ^= nd[r][i];
        }
    }
    return ret;
}
int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        memset(d, 0, sizeof(d));
        memset(pos, 0, sizeof(pos));
        int n, m, a;
        scanf("%d %d", &n, &m);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a);
            add(a, i);
        }
        int last = 0;
        while(m--) {
            int op, l, r;
            scanf("%d", &op);
            if(op == 0) {
                scanf("%d %d", &l, &r);
                l = (l ^ last) % n + 1;
                r = (r ^ last) % n + 1;
                if(l > r) {
                    int tmp = l;
                    l = r;
                    r = tmp;
                }
                last = ask(l, r);
                printf("%d\n", last);
            }
            else {
                scanf("%d", &a);
                a ^= last;
                n++;
                add(a, n);
            }
        }
    }
    return 0;
}
posted @ 2020-03-31 22:27  小饭hhh  阅读(272)  评论(0编辑  收藏  举报