Wannafly挑战赛14 并查集+线性基合并

链接: https://www.nowcoder.com/acm/contest/81/E
来源:牛客网

题目描述

给一个1-base数组{a},有N次操作,每次操作会使一个位置无效。一个区间的权值定义为这个区间里选出一些数的异或和的最大值。求在每次操作前,所有不包含无效位置的区间的权值的最大值。

输入描述:

 
  

第一行读入一个正整数(1 <= n <= 105)

第二行读入n个正整数,第i个表示a[i](0<= a[i] <= 109)

第三行读入n个正整数,第i个表示x[i]即第i次操作的位置,保证x[i]互不相同。

输出描述:

输出n行答案
示例1

输入

10
169 816 709 896 58 490 97 254 99 796 
4 2 3 10 5 6 1 8 9 7

输出

1023
994
994
994
490
490
254
254
99
97
 

题解:由于每次顺序已知,所以我们从后往前来,如果当前这个位置的前面或者后面的数,已经存在,则可以合并区间,进行线型基求解最大值。

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5 + 7;
const int N = 30;

int par[maxn];
int num[maxn];
int pos[maxn];
int res[maxn];
int find(int x)
{
    return x == par[x] ? x : par[x] = find(par[x]);
}
struct linearBase
{
    int d[N+1];
    void init() {
        memset(d,0,sizeof(d));
    }
    void insert(int val) {
        for(int i = N;i >= 0;i --) {
            if(val&(1<<i)) {
                if(!d[i]) {
                    d[i] = val;
                    break;
                }
                val ^= d[i];
            }
        }
    }
    int query_max() {
        int res = 0;
        for(int i = N;i >= 0;i --) res = max(res, res ^ d[i]);
        return res;
    }
    void merge(linearBase& n) {
        for(int i = N;i >= 0;i --) {
            if(n.d[i]) insert(n.d[i]);
        }
    }
}Base[maxn];


int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1;i <= n;i ++) scanf("%d", &num[i]);
    for(int i = 1;i <= n;i ++) scanf("%d", &pos[i]);
    for(int now=0,i = n;i >= 1;i --) {
        int p = pos[i];
        par[p] = p;
        Base[p].insert(num[p]);
        if(par[p-1]) {
            int fa = find(p-1);
            Base[fa].merge(Base[p]);
            par[p] = fa;
        }
        if(par[p+1]) {
            int fa = find(p+1);
            int ff = find(p);
            Base[fa].merge(Base[ff]);
            par[ff] = fa;
        }
        now = max(now, Base[find(p)].query_max());
        res[i] = now;
    }
//    for(int i = 1;i <= n;i ++) printf("%d ",find(i));puts("");
    for(int i = 1;i <= n;i ++) printf("%d\n", res[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36876305/article/details/80061213