codeforces 1100F Ivan and Burgers 线性基 离线

题目传送门

题意:

  给出 n 个数,q次区间查询,每次查询,让你选择任意个下标为 [ l , r ] 区间内的任意数,使这些数异或起来最大,输出最大值。

思路:离线加线性基。

线性基学习博客1

线性基学习博客2

对于此题,先把区间按照 r 从小到大排序,然后依次处理这些区间,每次插入线性基时,优先保留下标比较大的线性基。查询时,只异或上下标大于 l 的值。

记住异或的符号的优先级很低,所以  if( res^p[i] > res )这样的代码是会wa死的,要注意(这道题这么写,样例都过不了)

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll; 
const int maxn=5e5+10;
int a[maxn],q,n,p[30],pos[30],ans[maxn];
struct node{
    int l,r,id;
    friend bool operator<(const node &a,const node &b)
    {
        return a.r<b.r;
    }
}op[maxn]; 
void init(){
    clr(p,0);
}
void add(int val,int id){
    for(int i=20;i>=0;i--)
    {
        if(val&(1<<i))
        {
            if(!p[i]){
                p[i]=val,pos[i]=id;
                break;
            }
            if(pos[i]<id){
                swap(pos[i],id),swap(val,p[i]);
            }
            val^=p[i];
        }
    }
}
int query(int l)
{
    int res=0;
    for(int i=20;i>=0;i--)
    {
        if(pos[i]>=l)
        {
            if((res^p[i])>res)
            {
                res=res^p[i];
            }
        }
    }
    return res;
}
int main(){
    while(cin>>n)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        cin>>q;
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d",&op[i].l,&op[i].r);
            op[i].id=i;
        }
        sort(op+1,op+1+q);
        int l=1;
        for(int i=1;i<=q;i++)
        {
            while(l<=op[i].r&&l<=n)
            {
                add(a[l],l);
                l++;
            }
            ans[op[i].id]=query(op[i].l);
        }
        for(int i=1;i<=q;i++)
        {
            printf("%d
",ans[i]);
        }
    }
}
View Code
原文地址:https://www.cnblogs.com/mountaink/p/10348254.html