Loading

2021牛客多校第三场 I. Kuriyama Mirai and Exclusive Or (位运算+差分)

题意就是给你一个长度为n的数组,之后有两种操作,第一种是[L, R]都异或上x,第二种是[L, R]异或上x, x+1, x+2, x+3...

对于第一个操作我们非常容易就能操作,即异或差分数组。

但是对于第二个操作我们就比较头疼了,我们要怎么把 + 符号去掉变成 ^ 呢。 (因为异或是不满足分配律的所以我们需要想办法把这个+号去掉。

考虑到如果我们将 x 分为 k块(k为x的二进制1的个数)。

为什么这样分呢,因为我们发现假设 lowbit(x) = k,  那么a1 ^ (x + 1) 就会等价于 a1 ^ x ^ 1因为在lowbit前面的都是0,0异或任何数字就是加上这个数字。

并且我们设置一个标记数组flag[i][j],表示从i位置开始,需要往长度为2的 j 次的块上,异或上0, 1, 2..., 2的 j 次-1

 

所以操作2,其实就是往块的两边^ 2的k次,之后再给块的开头打上标记。

之后考虑如何将标记下传到原数组。这里其实像是一个倍增的思想,也很像线段树里的push_down,就是说如果flag[ i ] [ j ]有标记的话,就意味着,i  -  i+2的(j-1)次, i+2的(j-1)次 - i + 2的 j 次上都会需要有这个操作。

于是我们就可以将flag[ i ] [ j ]下放到, flag[ i ] [ j-1]和 flag[ i + 2的j-1次] [ j-1 ],同时对差分数组的 i + 2的j-1次与i + 2的j次的位置异或上 2的j-1次。就相当于是,往后半个块上异或上 2 的 j -1次。

参考博客:https://blog.csdn.net/weixin_45775438/article/details/119654815?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-8.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-8.no_search_link

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f; ///1061109567
const int maxn = 6e5 + 10;

int chafen[maxn];
int flag[maxn][21];
int a[maxn], pw[21];

int main() {
    int n, q; scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
    pw[0] = 1;
    for (int i = 1; i <= 20; ++ i) pw[i] = pw[i-1]*2;

    while (q--) {
        int op; scanf("%d", &op);
        int l, r, x; scanf("%d%d%d", &l, &r, &x);
        if (op == 0) {
            chafen[l] ^= x;
            chafen[r+1] ^= x;
        }
        else {
            for (int j = 0; j <= 20; ++ j) {
                if (((x >> j) & 1) && (l + pw[j] - 1) <= r) {
                    chafen[l] ^= x;
                    chafen[l+pw[j]] ^= x;
                    flag[l][j] ^= 1;

                    x += pw[j];
                    l += pw[j];
                }
            }
            for (int j = 20; j >= 0; j --) {
                if (l + pw[j]-1 <= r) {
                    chafen[l] ^= x;
                    chafen[l+pw[j]] ^= x;

                    flag[l][j] ^= 1;

                    x += pw[j];
                    l += pw[j];
                }
            }
        }
    }
    for (int j = 20; j >= 1; j --) {
        for (int i = 1; i <= n; ++ i) {
            if (flag[i][j]) {
                flag[i][j-1] ^= 1;
                flag[i+pw[j-1]][j-1] ^= 1;

                chafen[i+pw[j-1]] ^= pw[j-1];
                chafen[i+pw[j]] ^= pw[j-1];
            }
        }
    }
    for (int i = 1; i <= n; ++ i) {
        chafen[i] ^= chafen[i-1];
        printf("%d%c", a[i] ^ chafen[i], " \n"[i==n]);
    }
    return 0;
}

 

posted @ 2021-10-13 11:38  ViKyanite  阅读(68)  评论(0编辑  收藏  举报