【2017西安邀请赛:A】XOR(线段树+线性基)

前言:虽然已经有很多题解了,但是还是想按自己的理解写一篇。

思路:首先分析题目

   一、区间操作 —— 线段树

   二、异或操作 —— 线性基

   这个两个不难想,关键是下一步的技巧

    “或”运算 就是两个数的二进制中,对应位 只要有1,那么就是该位结果就是 1,所以要想k“或”运算后的结果尽量大,

   就需要异或出的数,各个位上的1尽量多。

   线性基的操作,可以求出区间最大异或和,但是我们需要的结果是  “或”运算。

   所以我们可以将 k 取反,然后把所有数在加入线性基之前,全部 “与”运算一遍,再加入线性基。

   这样,线性基中的每一位,全部都是能使得k变大的数了,因为k的二进制上的每一位 1 的位置,线性基中都是0。

   所以,我们只需要求, k 异或 线性基中最大异或和 。

  

//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include<unordered_set>

using namespace std;
typedef double dou;
typedef long long ll;
typedef pair<int, int> pii;
typedef map<int, int> mii;

#define pai acos(-1.0)
#define M 10050
#define inf 0x3f3f3f3f
#define mod 1000000007
#define IN inline
#define W(a) while(a)
#define lowbit(a) a&(-a)
#define left k<<1
#define right k<<1|1
#define lson L, mid, left
#define rson mid + 1, R, right
#define ms(a,b) memset(a,b,sizeof(a))
#define Abs(a) (a ^ (a >> 31)) - (a >> 31)
#define random(a,b) (rand()%(b+1-a)+a)
#define false_stdio ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

int T;
int n, q, k;
int tmp, x, y, z;

struct Data {
    int num[35];
    void insert(int t) {
        for (int i = 31; i >= 0; i--) {
            if (t >> i & 1) {
                if (!num[i]) { num[i] = t; break; }
                t ^= num[i];
            }
        }
    }
}tree[M << 2], ans;

IN void Updata(int L, int R, int k,int pos) {
    tree[k].insert(tmp);
    if (L == R)return;
    int mid = L + R >> 1;
    if (pos <= mid)Updata(lson, pos);
    else Updata(rson, pos);
}

IN void Query(int L, int R, int k) {
    if(x<=L && R<=y){
        for (int i = 31; i >= 0; i--) {
            if (tree[k].num[i])ans.insert(tree[k].num[i]);
        }
        return;
    }
    int mid = L + R >> 1;
    if (x <= mid)Query(lson);
    if (y > mid)Query(rson);
}

IN int read() {//快读
    int v = 0, f = 0; char ch = getchar();
    W(!isdigit(ch)) { f |= ch == ‘-‘; ch = getchar(); }
    W(isdigit(ch)) { v = (v << 3) + (v << 1) + (ch ^ 48); ch = getchar(); }
    return f ? -v : v;
}

int main() {
    T = read();
    W(T--) {
        n = read(), q = read(), k = read();
        for (int i = 1; i <= n; i++) {
            tmp = read();
            tmp &= (~k);//关键的一步
            Updata(1, n, 1, i);
        }
        W(q--) {
            ms(ans.num, 0);
            x = read(), y = read();
            Query(1, n, 1);
            z = k;
            for (int i = 31; i >= 0; i--)z = max(z, z ^ ans.num[i]);
            printf("%d\n", z);
        }
    }
    return 0;
}

   

   

原文地址:https://www.cnblogs.com/caibingxu/p/11788485.html

时间: 2024-10-30 01:36:36

【2017西安邀请赛:A】XOR(线段树+线性基)的相关文章

[HDU4867]Xor (线段树分治+类数位dp)

[HDU4867]Xor (线段树分治+类数位dp) 提供一种\((m+n) log a log m\)带有常数约\(\frac{1}{log n}\)的算法 处理询问,将后来加入的数算进序列中,则每个数\(a_i\)都有一段出现的区间\([L,R]\) 离线询问后,我们考虑用线段树分治将这些数加入到询问区间上 由于最多只有5000个修改操作,事实上这些数在线段树上覆盖的区间最多只有\(10000logm\)个,并且有着极其不满的常数(因为每个位置上的数都由多段区间组合而来,总长为\(m\),或

【Educational Codeforces Round 37】F. SUM and REPLACE 线段树+线性筛

题意 给定序列$a_n$,每次将$[L,R]$区间内的数$a_i$替换为$d(a_i)$,或者询问区间和 这题和区间开方有相同的操作 对于$a_i \in (1,10^6)$,$10$次$d(a_i)$以内肯定可以最终化为$1$或者$2$,所以线段树记录区间最大值和区间和,$Max\le2$就返回,单点暴力更新,最后线性筛预处理出$d$ 时间复杂度$O(m\log n)$ 代码 #include <bits/stdc++.h> using namespace std; typedef long

POJ - 2886线段树+线性筛

题意就是给你n个人,每个人有一个名字和A,如果A为正则向左找第A个,否则向右找第-A个,每找到一个就出列,然后第i个人出列的F(i)是i的所有因子个数 输出最大的F(i)和对应的名字 先用线性筛找出第几个出列的值最大maxn,那么求到maxn就可以了. 用线段树记录空位,k表示当前需要从剩余人第几个位置寻找,只要推出k,则转化为线段树的求位置的模型 #include<iostream> #include<cstdio> #include<cstring> using n

【洛谷】P2073 送花 [2017年6月计划 线段树01]

P2073 送花 题目背景 小明准备给小红送一束花,以表达他对小红的爱意.他在花店看中了一些花,准备用它们包成花束. 题目描述 这些花都很漂亮,每朵花有一个美丽值W,价格为C. 小明一开始有一个空的花束,他不断地向里面添加花.他有以下几种操作: 操作 含义 1 W C 添加一朵美丽值为W,价格为C的花. 3 小明觉得当前花束中最便宜的一朵花太廉价,不适合送给小红,所以删除最便宜的一朵花. 2 小明觉得当前花束中最贵的一朵花太贵,他心疼自己的钱,所以删除最贵的一朵花. -1 完成添加与删除,开始包

洛谷P1774 最接近神的人_NOI导刊2010提高(02) [2017年6月计划 线段树03]

P1774 最接近神的人_NOI导刊2010提高(02) 题目描述 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案.而石门上方用古代文写着“神的殿堂”.小FF猜想里面应该就有王室的遗产了.但现在的问题是如何打开这扇门…… 仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的.而最聪明的人往往通过一种仪式选拔出来.仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即

洛谷P2826 [USACO08NOV]光开关Light Switching [2017年6月计划 线段树02]

P2826 [USACO08NOV]光开关Light Switching 题目描述 Farmer John tries to keep the cows sharp by letting them play with intellectual toys. One of the larger toys is the lights in the barn. Each of the N (2 <= N <= 100,000) cow stalls conveniently numbered 1..N

codeforces CF920F SUM and REPLACE 线段树 线性筛约数

$ \Rightarrow $ 戳我进CF原题 F. SUM and REPLACE time limit per test: 2 seconds memory limit per test: 256 megabytes input: standard input output: standard output Let $ D(x) $ be the number of positive divisors of a positive integer $ x $ . For example, $

[六省联考2017]相逢是问候(线段树+拓展欧拉定理)

好题啊! 调了一个中午,发现有一条语句 \(RE\) 了.在 \(windows\) 下没关系,\(linux\) 下有问题,大大的问题. while(phi[tot]!=1) phi[++tot]=calc_phi(phi[tot-1]); 算是拓展欧拉定理的题吧.线段树只是一个工具,最主要还是暴力修改.因为 \(\varphi\) 不断套下去最多会有 \(\lfloor \log n\rfloor\) 层,所以我们对于每一层暴力算一遍,加上快速幂,时间复杂度 \(O(n\log^3 n)\)

[WC2011]最大XOR和路径 线性基

题面 题面 题解 其实是一个很重要的套路啦. 首先我们从s到t的一个基础路径肯定是一条链,在此基础上,我们唯一可以带来一些增益的走法就是在走这条链的基础上走一些环,因为xor的特点,来回走的路都相当于没走,而只有环可以做到不往回走却能回到原点. 因此只有走环才会给原来的路线带来改变,否则走了都等于没走. 因此我们将图上所有简单环异或后的01串加入线性基. 那么对于一条指定的链,所以环可以带给它的最大增益可以用类似求最大异或和的方式来求. 所以我们还需要枚举每一条链? 其实不用. 因为所有链的起点