题意:
给出 n 个数,q次区间查询,每次查询,让你选择任意个下标为 [ l , r ] 区间内的任意数,使这些数异或起来最大,输出最大值。
思路:离线加线性基。
对于此题,先把区间按照 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\n",ans[i]); } } }
原文地址:https://www.cnblogs.com/mountaink/p/10348254.html
时间: 2024-11-09 03:46:28