題意:給定N個數,Q次詢問,求區間最大異或和。c++
思路:一開始想的線性基+線段樹。單次線性基合併的複雜度爲20*20,結合線段樹,複雜度爲O(NlogN*20*20);顯然,超時。ide
超時代碼:ui
#include<bits/stdc++.h> #define pb push_back #define rep(i,a,b) for(int i=a;i<=b;i++) #define rep2(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=2000010; int a[maxn]; vector<int>G[maxn]; void read(int &x){ x=0; char c=getchar(); while(c>'9'||c<'0') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); } void add(vector<int>&Now,vector<int>&p) { rep(i,0,20){ int x=p[i]; if(!x) continue; rep2(j,20,0){ if(x&(1<<j)){ if(Now[j]) x^=Now[j]; else { Now[j]=x;break;} } } } } void build(int Now,int L,int R) { rep(i,0,20) G[Now].pb(0); if(L==R){ int x=a[L]; if(!x) return; rep2(j,20,0){ if(x&(1<<j)){ if(G[Now][j]) x^=G[Now][j]; else { G[Now][j]=x;break;} } } return ; } int Mid=(L+R)>>1; build(Now<<1,L,Mid); build(Now<<1|1,Mid+1,R); G[Now]=G[Now<<1]; add(G[Now],G[Now<<1|1]); } void query(int Now,int L,int R,int l,int r,vector<int>& res) { if(l<=L&&r>=R) { res=G[Now]; return ;} int Mid=(L+R)>>1; rep(i,0,20) res.pb(0); if(l<=Mid){ vector<int>t; query(Now<<1,L,Mid,l,r,t); res=t; } if(r>Mid) { vector<int>t; query(Now<<1|1,Mid+1,R,l,r,t); add(res,t); } } int main() { int N,M,L,R; scanf("%d",&N); rep(i,1,N) read(a[i]); build(1,1,N); scanf("%d",&M); while(M--){ read(L); read(R); vector<int>t; query(1,1,N,L,R,t); int res=0; rep2(i,20,0) if((res^t[i])>res) res^=t[i]; printf("%d\n",res); } return 0; }
咱們考慮離線,把全部詢問按右端點排序,而後從左到有處理詢問,對於當前詢問[L,R];咱們把[1,R]全部的數加入線性基,關鍵是對於每一位,咱們保留其爲位置,這裏確定是貪心地保留越後面的位置越優。 那麼查詢的時候,若是一個線性基裏的數位置>=L,則能夠考慮更新答案。spa
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define rep2(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=500010; struct in{ int l,r,id; friend bool operator< (in w,in v){ return w.r<v.r;} }s[maxn]; int N,Q,ans[maxn],a[maxn],p[21],pos[21]; void add(int x,int id) { rep2(i,20,0) if(x&(1<<i)){ if(!p[i]){ p[i]=x; pos[i]=id; return ; } if(pos[i]<id) swap(p[i],x),swap(pos[i],id); x^=p[i]; } } int query(int id) { int res=0; rep2(i,20,0) if(pos[i]>=id&&(res^p[i])>res) res^=p[i]; return res; } int main() { scanf("%d",&N); rep(i,1,N) scanf("%d",&a[i]); scanf("%d",&Q); rep(i,1,Q) scanf("%d%d",&s[i].l,&s[i].r),s[i].id=i; sort(s+1,s+Q+1); int L=1; rep(i,1,Q){ while(L<=s[i].r&&L<=N) add(a[L],L),++L; ans[s[i].id]=query(s[i].l); } rep(i,1,Q) printf("%d\n",ans[i]); return 0; }
那麼同理,不難想出在線的作法,咱們紀錄一個前綴和 線性基,任然保留最大的位置。code
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define rep2(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=500010; int p[maxn][21],pos[maxn][21]; int main() { int N,Q,L,R,x; scanf("%d",&N); rep(i,1,N) { rep(j,0,20) p[i][j]=p[i-1][j],pos[i][j]=pos[i-1][j]; scanf("%d",&x); int ti=i; rep2(j,20,0){ if(x&(1<<j)){ if(!p[i][j]) { p[i][j]=x; pos[i][j]=ti; break; } if(pos[i][j]<ti) swap(p[i][j],x),swap(pos[i][j],ti); x^=p[i][j]; } } } scanf("%d",&Q); rep(i,1,Q) { scanf("%d%d",&L,&R); int res=0; rep2(j,20,0) if(pos[R][j]>=L&&(res^p[R][j])>res) res^=p[R][j]; printf("%d\n",res); } return 0; }