国际惯例的题面:
异或凑出一个数,显然是线性基了。
显然我们能把区间[l,r]的数全都扔进一个线性基,然后试着插入w,如果能插入,则说明w不能被这些数线性表出,那么就要输出"NO"了。
然而怎么得到这个线性基?我们有两种很显然的暴力:线段树和单调莫队。然而亲测它们都不能AC......(不排除我写丑了)
考虑思考一下性质:如果我们能对于每个结束位置,用这个位置前面尽可能靠后的数构造出一个线性基,那么我们查询的时候是不是就能取出结束位置为r的线性基限制用的数出现位置不能早于l,然后直接查询就好了呢?(这种思想在Bzoj3514: Codechef MARCH14 GERALD07加强版)中也用到过。
好,如果这样做的话,怎么从结束位置为i-1的线性基得到结束位置为i的线性基呢?
我们可以把结束位置为i-1的线性基拆了,然后贪心按照出现位置从大到小插入,正确性显然,复杂度O(900n)。
查询的时候怎么办?我们把结束位置为r的线性基中出现位置>l的数拆出来,插入一个新线性基,进行查询,复杂度O(900q)。
非常不幸的是,这样仍然不能AC。虽然我已经千方百计卡常数了。
我们现在在维护出现最晚的线性无关的30个数,考虑我们维护序列最大的30个数怎么维护。
只有30个数,我们再写个堆(priority_queue?假装你是Pascal党好了)什么的显然不必要了。直接在插入的时候从大到小进行一轮冒泡排序,用当前的大数替换小数就好。
对于这个线性基,我们也能这样做。
我们从高位向低位扫描这个线性基,如果我们当前的数能被放入某个位置的话,如果这个位置为空,则直接放入;否则比较出现位置,如果当前数出现较为靠后的话,则把当前数和这个位置的数swap一下,然后从下一位继续进行插入。
然后我们会发现这样构造的线性基还会有另一个更好的性质:高位上的数出现尽量靠后。
查询的时候,从高位到低位进行查询。如果凑出w需要高位的某个数而这个数出现位置<l,那么这一位无论如何都消不掉了,直接输出'NO'即可。
这样我们就把复杂度优化为了O(30n+30q),能够轻松AC。
暴力线段树代码:
1 #pragma GCC optimize("Ofast,no-stack-protector") 2 #pragma GCC optimize("-funsafe-loop-optimizations") 3 #pragma GCC optimize("-funroll-loops") 4 #pragma GCC optimize("-fwhole-program") 5 #include<cstdio> 6 #include<cstring> 7 #include<cctype> 8 #define bool unsigned char 9 typedef unsigned int ui; 10 const int maxn=1048577,maxl=31; 11 12 ui in[maxn>>1],bit[maxl]; 13 14 struct LinearBase { 15 ui dat[maxl]; 16 __inline const ui& operator [] (const ui &x) const { return dat[x]; } 17 __inline bool insert(ui x) { 18 for(ui i=30;~i;i--) if( x & bit[i] ) { 19 if( !dat[i] ) return dat[i] = x , 1; 20 else x ^= dat[i]; 21 } 22 return 0; 23 } 24 __inline void merge(const LinearBase &r) { 25 for(ui i=30;~i;i--) if( r[i] ) insert(r[i]); 26 } 27 __inline void reset() { 28 memset(dat,0,sizeof(dat)); 29 } 30 }ans; 31 32 struct SegmentTree { 33 LinearBase dat[maxn]; 34 #define lson(pos) (pos<<1) 35 #define rson(pos) (pos<<1|1) 36 __inline void build(ui pos,ui l,ui r) { 37 if( l == r ) return void(dat[pos].insert(in[l])); 38 const ui mid = ( l + r ) >> 1; 39 build(lson(pos),l,mid) , build(rson(pos),mid+1,r); 40 dat[pos] = dat[lson(pos)] , dat[pos].merge(dat[rson(pos)]); 41 } 42 __inline void query(ui pos,ui l,ui r,const ui &ll,const ui &rr) { 43 if( ll <= l && r <= rr ) return ans.merge(dat[pos]); 44 const ui mid = ( l + r ) >> 1; 45 if( ll <= mid ) query(lson(pos),l,mid,ll,rr); 46 if( mid < rr ) query(rson(pos),mid+1,r,ll,rr); 47 } 48 }sgt; 49 50 __inline unsigned char nextchar() { 51 static const ui BS = 1 << 18; 52 static unsigned char buf[BS],*st,*ed; 53 if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin); 54 return st == ed ? 0 : *st++; 55 } 56 __inline ui getint() { 57 ui ret = 0; 58 unsigned char ch; 59 while( !isdigit(ch=nextchar()) ) ; 60 do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) ); 61 return ret; 62 } 63 64 int main() { 65 static ui n,q,l,r,w; 66 n = getint(); 67 for(ui *st=in+1,*ed=st+n;st!=ed;*st++=getint()); 68 for(ui i=0;i<30;i++) bit[i] = 1 << i; 69 sgt.build(1,1,n) , q = getint(); 70 while(q--) { 71 l = getint() , r = getint() , w = getint() , ans.reset(); 72 sgt.query(1,1,n,l,r); 73 puts(ans.insert(w)?"NO":"YES"); 74 } 75 return 0; 76 }
暴力重构线性基:
1 #pragma GCC optimize("Ofast") 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cctype> 7 #define debug cout 8 using namespace std; 9 const int maxn=5e5+1e2,maxl=31; 10 const int inf=0x3f3f3f3f; 11 12 int in[maxn],seq[maxl+2],sql; 13 14 struct LinearBase { 15 int dat[maxl],bel[maxl]; 16 inline bool insert(int id,int val) { 17 for(int i=30;~i;i--) if( val & ( 1 << i ) ) { 18 if( !dat[i] ) { 19 dat[i] = val , bel[i] = id; 20 return 1; 21 } else val ^= dat[i]; 22 } 23 return 0; 24 } 25 inline int findremove(int val) { 26 int mx = inf; 27 for(int i=30;~i;i--) if( bel[i] && ( val & ( 1 << i ) ) ) mx = min( mx , bel[i] ); 28 return mx; 29 } 30 inline void output(int lim) { 31 for(int i=30;~i;i--) if( bel[i] >= lim ) seq[++sql] = bel[i]; 32 } 33 inline bool insert(int val) { 34 for(int i=30;~i;i--) if( val & ( 1 << i ) ) { 35 if( !dat[i] ) return dat[i] = val , 1; 36 else val ^= dat[i]; 37 } 38 return 0; 39 } 40 inline void reset() { 41 memset(dat,0,sizeof(dat)) , memset(bel,0,sizeof(bel)); 42 } 43 }lb[maxn],tp; 44 45 inline char nextchar() { 46 static const int BS = 1 << 18; 47 static char buf[BS],*st,*ed; 48 if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin); 49 return st == ed ? 0 : *st++; 50 } 51 inline int getint() { 52 int ret = 0; 53 char ch; 54 while( !isdigit(ch=nextchar()) ) ; 55 do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) ); 56 return ret; 57 } 58 59 int main() { 60 static int n,q,l,r,w; 61 n = getint(); 62 for(int i=1;i<=n;i++) { 63 lb[i] = lb[i-1]; 64 if( !lb[i].insert(i,in[i]=getint()) ) { 65 sql = 0 , lb[i-1].output(0) , lb[i].reset(); 66 lb[i].insert(i,in[i]) , std::sort(seq+1,seq+1+sql); 67 for(int j=sql;j;j--) lb[i].insert(seq[j],in[seq[j]]); 68 } 69 } 70 q = getint(); 71 while(q--) { 72 l = getint() , r = getint() , w = getint(); 73 sql = 0 , lb[r].output(l) , tp.reset(); 74 for(int i=1;i<=sql;i++) tp.insert(in[seq[i]]); 75 puts(tp.insert(w)?"NO":"YES"); 76 } 77 return 0; 78 }
正解代码:
1 #pragma GCC optimize("Ofast") 2 #include<cstdio> 3 #include<algorithm> 4 #include<cctype> 5 const int maxn=5e5+1e2,maxl=31; 6 const int inf=0x3f3f3f3f; 7 8 int in[maxn],seq[maxl+2],sql; 9 bool vis[maxn]; 10 11 struct LinearBase { 12 int dat[maxl],bel[maxl]; 13 inline void insert(int id,int val) { 14 for(int i=30;~i;i--) if( val & ( 1 << i ) ) { 15 if( !dat[i] ) { 16 dat[i] = val , bel[i] = id; 17 return; 18 } else { 19 if( bel[i] < id ) std::swap(bel[i],id) , std::swap(val,dat[i]); 20 val ^= dat[i]; 21 } 22 } 23 } 24 inline bool query(int val,int lim) { 25 for(int i=30;~i;i--) if( val & ( 1 << i ) ) { 26 if( !dat[i] || bel[i] < lim ) return 1; 27 val ^= dat[i]; 28 } 29 return 0; 30 } 31 }lb[maxn],tp; 32 33 inline char nextchar() { 34 static const int BS = 1 << 18; 35 static char buf[BS],*st,*ed; 36 if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin); 37 return st == ed ? 0 : *st++; 38 } 39 inline int getint() { 40 int ret = 0; 41 char ch; 42 while( !isdigit(ch=nextchar()) ) ; 43 do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) ); 44 return ret; 45 } 46 47 int main() { 48 static int n,q,l,r,w; 49 n = getint(); 50 for(int i=1;i<=n;i++) lb[i] = lb[i-1] , lb[i].insert(i,in[i]=getint()); 51 q = getint(); 52 while(q--) { 53 l = getint() , r = getint() , w = getint(), puts(lb[r].query(w,l)?"NO":"YES"); 54 } 55 return 0; 56 }
明けの星が
启明的星辰
光を見せた
洒下丝丝光芒
よわい よわい
微微地 微微地
こころに降りそそぐ
纷纷洒落到我心房
でも時は
可有的时候
おなじ想いだけを
如果能够继续
あ…描き続ければ
描绘同样的思念…
誰も知らず
谁也不知道
日が射すまでに
直到太阳升起
そっと そっと
静静地 静静地
予感を感じてた
我感觉到一丝预感
こころが感じてた
我的心 有了一丝预感