• HDU 6845(杭电多校7-B)(线性基)


    这不是题解, 只是个人记录一个小知识点


    起因是不知道题解里那句 "对于 (n) 个人的每个前缀,求出从后往前插入的线性基,并记录每个基是哪个人提供的,这是一个经典算法" 所指的经典算法是啥, 读了代码之后知道, 原来算法流程是这样的: 从前往后扫, 当前是第 (i) 个向量 (x) 时, 按正常插入线性基从高位往低位扫 x, 第 (j) 位遇到 (1) 时检查 (bas[j][0]) 是否为 (0), 不为 (0) 时, (bas[j][0] = x), (bas[j][1]=i); 否则, 执行 (if(ti>bas[j][1]) swap(bas[j][0],x),swap(bas[j][1],ti)), (ti) 初值为 (i), 后面正常 x^=bas[j][0], 继续扫.

    意思就是说我新来一个向量 (a[i]=x), 接管了前面的 (a[k]=y) 向量对位置 (j) 的最后控制权, 但是 a[k]=x^y 可以去接管剩余的低位. 乍一看会觉得明明是 (a[i]) 提供了低位的数, 但"控制权"归 (a[k]), 这是因为 (a[k]) 通过控制第 (j) 位来间接控制了 (a[i]). 好吧可能我这段话是在放屁, 但是, emm, 反正我信了.

    下面的代码是在标程基础上删了一些没必要的部分.

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    
    const int maxn = 1e5 + 5;
    
    int bas[maxn][30][2], p[maxn], n, m, x, y, q, opt, b[maxn], w, ti, T;
    
    int main() {
        scanf("%d", &T);
        while (T--) {
            scanf("%d%d", &n, &q);
            for (int i = 1; i <= n; i++) {
                scanf("%d%d", &m, &p[i]);
                b[i] = b[i - 1];
                for (int k = 0; k < 30; k++)
                    bas[i][k][0] = bas[i - 1][k][0],
                    bas[i][k][1] = bas[i - 1][k][1];
                for (int j = 1; j <= m; j++) {
                    scanf("%d%d", &x, &y);
                    b[i] ^= x;
                    y ^= x;
                    ti = i;
                    for (int k = 29; k >= 0; k--) {
                        if (!(y >> k & 1)) continue;
                        if (!bas[i][k][0]) {
                            bas[i][k][0] = y;   //该位置的向量是什么
                            bas[i][k][1] = ti;  //归哪个向量管
                            break;
                        } else {
                            if (bas[i][k][1] < ti)
                                swap(y, bas[i][k][0]), swap(ti, bas[i][k][1]);
                            y ^= bas[i][k][0];
                        }
                    }
                }
            }
            for (int i = 1; i <= q; i++) {
                scanf("%d%d%d", &opt, &x, &y);
                if (opt == 1)
                    p[x] = y;
                else {
                    scanf("%d", &w);
                    w ^= b[y] ^ b[x - 1];
                    for (int j = 29; j >= 0; j--) {
                        if (!bas[y][j][0] || bas[y][j][1] <= x - 1) continue;
                        if ((w ^ p[bas[y][j][1]]) >> j & 1) w ^= bas[y][j][0];
                    }
                    printf("%d
    ", w);
                }
            }
        }
    }
    
    
  • 相关阅读:
    时间相关
    mongodb数据库怎么迁移
    删除项目中所有的__pycache__ 文件
    获取请求参数
    Linux VIM python 自动补全插件:pydiction
    Linux的环境变量.bash_profile .bashrc profile文件
    Linux下查看CPU型号,内存大小,硬盘空间的命令(详解)
    python3的一些文件操作的脚手架
    Python time strptime()方法 时间操作
    我看《架构漫谈》——1
  • 原文地址:https://www.cnblogs.com/linqi05/p/13642883.html
Copyright © 2020-2023  润新知