2019杭电暑期多校第一场 B:Operation(贪心+前缀线性基求最大异或和)

【题目】

Operation

【题解】

原题:CF1100F

官方题解:贪心地维护序列的前缀线性基 (上三角形态),对于每个线性基,将出现位置靠右的数字尽可能地放在高位,也就是说在插入新数字的时候,要同时记录对应位置上数字的出现位置,并且在找到可以插入的位置的时候,如果新数字比位置上原来的数字更靠右,就将该位置上原来的数字向低位推。在求最大值的时候,从高位向低位遍历,如果该位上的数字出现在询问中区间左端点的右侧且可以使答案变大,就异或到答案里。对于线性基的每一位,与它异或过的线性基更高位置上的数字肯定都出现在它右侧 (否则它就会被插入在那个位置了),因此做法的正确性显然。

代码借鉴于https://blog.csdn.net/Dillonh/article/details/96878675

【代码】

#include
using namespace std;
const int maxn=1e6+10;
int a[maxn],b[32],pos[32];
int base[maxn][32],las[maxn][32];
void add(int val,int p)
{
    for(int i=30;i>=0;i--){
        if(val&(1ll<=0;i--)
            b[i]=pos[i]=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            add(a[i],i);
            for(int j=30;j>=0;j--)
                base[i][j]=b[j],las[i][j]=pos[j];
        }
        int lastans=0;
        while(q--){
            int op; scanf("%d",&op);
            if(op){
                ++n;
                int x; scanf("%d",&x);
                x^=lastans;
                add(x,n);
                for(int i=30;i>=0;i--)
                    base[n][i]=b[i],las[n][i]=pos[i];
            }
            else{
                int l,r; scanf("%d%d",&l,&r);
                l=(l^lastans)%n+1,r=(r^lastans)%n+1;
                if(l>r) swap(l,r);
                lastans=0;
                for(int i=30;i>=0;i--){
                    if(las[r][i]>=l&&(lastans^base[r][i])>lastans)
                        lastans^=base[r][i];
                }
                printf("%d\n",lastans);
            }
        }
    }
    return 0;
}

 

你可能感兴趣的:(2019杭电暑期多校第一场 B:Operation(贪心+前缀线性基求最大异或和))