国际惯例的题面:
51Nod1577 异或凑数 线性基 构造
异或凑出一个数,显然是线性基了。
显然我们能把区间[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 }
View Code

相关文章:

  • 2021-08-01
  • 2021-05-18
  • 2021-10-24
  • 2021-09-19
  • 2021-12-17
  • 2021-08-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-01-17
  • 2021-04-12
  • 2021-10-27
  • 2021-07-28
  • 2022-02-28
  • 2021-09-12
  • 2022-12-23
相关资源
相似解决方案