51nod 1577 异或凑数(线性基)

分析:如果能知道区间线性基,问题就解决了,所以一开始有个naive的想法,搞个线性基线段树,然而复杂度(32*nlogn),果断T。。。

正解是预处理后缀线性基,并且每个基中的每一个分量位置尽量靠前,然后把k丢到左端点对应的线性基里跑,如果k最后不为0或者需要异或的位置超过了r,答案就是NO。

这样的后缀线性基可以从后面开始处理,插入x时,如果某一位已经有数且在数组中的位置在x之后,把x放入线性基替换掉这个数,然后用这个数接着跑。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define SWAP(x, y)x ^= y, y ^=x, x ^= y;
 5 using namespace std;
 6 const int maxn = 5e5 + 5, inf = 1e9;
 7 int n;
 8 struct LinearBase{
 9     int a[32], n, loca[32];
10     LinearBase(){
11         memset(a, 0, sizeof(a));
12         memset(loca, 0, sizeof(loca));
13         n = 0;
14     }
15     void insert(int x, int k){
16         int cur_loca = k;
17         int d = 31;
18         while(x && d >= 0){
19             if(x & (1 << d)){
20                 if(a[d]){
21                     if(cur_loca < loca[d]){
22                         SWAP(loca[d], cur_loca);
23                         SWAP(a[d], x);
24                     }
25                     x ^= a[d];
26                 }else{
27                     loca[d] = cur_loca;
28                     a[d] = x;
29                     n++;
30                     break;
31                 }
32             }
33             d--;
34         }
35     }
36     LinearBase operator = (LinearBase x){
37         x.n = n;
38         for(int i = 0; i < 32; i++)a[i] = x.a[i], loca[i] = x.loca[i];
39     }
40     int check(int k){
41         int d = 31, r_min = 0;
42         while(k && d>=0){
43             if(k & (1 << d)){
44                 if(!a[d])return inf;
45                 r_min = max(r_min, loca[d]);
46                 k ^= a[d];
47             }
48             d--;
49         }
50         if(k)return inf;
51         return r_min;
52     }
53 }lb[maxn];
54 int read(){
55     int ans = 0;
56     char last = ' ', ch = getchar();
57     while(ch >= '0' && ch <= '9')ans = ans * 10 + ch - '0', ch = getchar();
58     return ans;
59 }
60 bool check(int l, int r, int k){
61     LinearBase &b = lb[l];
62     if(b.check(k) <= r)return true;
63     return false;
64 }
65 int a[maxn];
66 int main(){
67 //    freopen("e:\\in.txt","r",stdin);
68     n = read();
69     for(int i = 1; i <= n; i++)a[i] = read();
70     lb[n].insert(a[n], n);
71     for(int i = n - 1; i >= 0; i--){
72         lb[i] = lb[i + 1];
73         lb[i].insert(a[i], i);
74     }
75     int m,l,r,k;
76     m = read();
77     for(int i = 0; i < m; i++){
78         l = read();r = read();k = read();
79         if(check(l, r, k))puts("YES");
80         else puts("NO");
81     }
82     return 0;
83 }

 

posted @ 2017-11-10 21:48  7391_KID  阅读(235)  评论(0编辑  收藏  举报