杭电多校HDU 6579 Operation (线性基 区间最大)题解

题意:

强制在线,求\(LR\)区间最大子集异或和

思路:

求线性基的时候,记录一个\(pos[i]\)表示某个\(d[i]\)是在某个位置更新进入的。如果插入时\(d[i]\)\(pos[i]\)小于我当前插入的\(pos[r]\),那么就用当前插入的数换出原来的\(d[i]\),继续进行插入并更新\(pos\),这样就能保证所有的异或和都没有丢失。这样我们只要每次保存出所有\(dn[r][maxn]\)表示最右边为\(r\)时的线性基就可以直接求出所有区间\([L,R]\)\(1 <= L <= R <= r\)。只需要满足\(pos[i] >= L\),当前找的线性基就是可以使用的线性基。

参考:

线性基 详细整理

代码:

#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<stack>
#include<vector>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
struct Liner_Basis{
    int d[32], nd[maxn][32];
    int pos[32], npos[maxn][32];
    int tot;
    void init(){
        memset(d, 0, sizeof(d));
        tot = 0;
    }
    void insert(int x, int r){
        int R = r;
        for(int i = 31; i >= 0; i--){
            if(x & (1LL << i)){
                if(!d[i]){
                    d[i] = x;
                    pos[i] = r;
                    break;
                }
                else if(pos[i] < r){    //把贡献早的换出
                    swap(pos[i], r);
                    swap(d[i], x);
                }
                x ^= d[i];  //原来的继续去贡献低位
            }
        }
        for(int i = 31; i >= 0; i--){  //保存当前线性基
            nd[R][i] = d[i];
            npos[R][i] = pos[i];
        }
    }

    int getMax(int l, int r){
        int ret = 0;
        for(int i = 31; i >= 0; i--){
            if(npos[r][i] >= l){
                ret = max(ret, ret ^ nd[r][i]);
            }
        }
        return ret;
    }

}lb;
int main(){
    int n, m;
    int T;
    scanf("%d", &T);
    while(T--){
       scanf("%d%d", &n, &m);
        lb.init();
        for(int i = 1; i <= n; i++){
            int c;
            scanf("%d", &c);
            lb.insert(c, 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) swap(l, r);
                last = lb.getMax(l, r);
                printf("%d\n", last);
            }
            else{
                scanf("%d", &l);
                l = l ^ last;
                lb.insert(l, ++n);
            }
        }
    }
    return 0;
}

posted @ 2019-07-26 10:05  KirinSB  阅读(435)  评论(0编辑  收藏  举报