2017icpc 西安 A.XOR

2017icpc 西安 A.XOR

题意:

长度为\(n\)的数组,\(q\)次询问,每次询问给出\(l,r\),从\([l,r]\)区间中选出一些数字使得这些数字的异或和或上\(k\)最大。

思路:

线性基是处理异或问题的好手,对于这种区间异或最大可以考虑用线段树维护线性基合并。

考虑怎么样能有\(k|(a_{i_1}\ xor\ a_{i_2}\ xor\ ,...,\ xor\ a_{i_m})\)最大。

最开始的想法是:搞出区间线性基,然后从高位一位一位的搜,如果\(k\)\(1\),那就不考虑线性基这一位,如果没有\(1\),就一定考虑,但是很快的就举出了反例。

考虑\(k\)需要什么?

\(k\)这一位有\(1\),我们可以尽量不管他,如果这一位没有\(1\),我们尽量从数字中选择把这位填上,实在没有就算了。

所以对\(k\)取反,对于线段树每个节点插入\(k\&a(i)\),每次询问查询\([l,r]\)最大结果,最后最结果或上\(k\)

正确性:

当对\(k\)取反后,对\(a(i)\)进行与运算,实际上就是在找\(a(i)\)这一位有没有\(1\)

同时也有可能将本来\(a(i)\)\(1\)的地方给取反后的\(k\)搞掉了,这不用担心,因为最后对答案或上\(k\),就回来了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4+10;

int n, m, k, a[maxn];
int l, r, ans;

struct LineBase
{
    int p[32];
    void init() {memset(p, 0, sizeof p);}
    void ins(int x)
    {
        for(int i = 30; i >= 0; i--)
        {
            if(x&(1<<i))
            {
                if(!p[i])
                {
                    p[i] = x;
                    return;
                }
                x ^= p[i];
            }
        }
    }

    int qmax()
    {
        int res = 0;
        for(int i = 30; i >= 0; i--)
            res = max(res, res^p[i]);
        return res;
    }
};

struct SegmentTree
{
    int l, r;
    LineBase t;
    #define lson (p<<1)
    #define rson (p<<1|1)
    #define l(x) tree[x].l
    #define r(x) tree[x].r
    #define t(x) tree[x].t
}tree[maxn<<2];

LineBase merge_base(LineBase a, LineBase b)
{
    for(int i = 30; i >= 0; i--)
        if(a.p[i]) b.ins(a.p[i]);
    return b;
}

void build(int p, int l, int r)
{
    l(p) = l, r(p) = r;
    t(p).init();
    if(l == r)
    {
        t(p).ins(a[l]);
        return;
    }
    int mid = (l+r)>>1;
    build(lson, l, mid);
    build(rson, mid+1, r);
    t(p) = merge_base(t(lson), t(rson));
}

LineBase ask(int p, int l, int r)
{
    if(l <= l(p) && r(p) <= r) return t(p);
    int mid = (l(p)+r(p))>>1;
    if(mid >= r) return ask(lson, l, r);
    else if(mid < l) return ask(rson, l, r);
    else return merge_base(ask(lson, l, r), ask(rson, l, r));
}

void solve()
{
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        a[i] = a[i]&(~k);
    }
    build(1, 1, n);
    while(m--)
    {
        scanf("%d%d", &l, &r);
        LineBase tmp = ask(1, l, r);
        ans = tmp.qmax();
        ans = ans|k;
        printf("%d\n", ans);
    }
}

int main()
{
    int T; scanf("%d", &T);
    while(T--) solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zxytxdy/p/12543871.html