【BZOJ2741】【块状链表+可持久化trie】FOTILE模拟赛L

Description

FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和。
即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r。
为了体现在线操作,对于一个询问(x,y):
l = min ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
r = max ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
其中lastans是上次询问的答案,一开始为0。

Input

第一行两个整数N和M。
第二行有N个正整数,其中第i个数为Ai,有多余空格。
后M行每行两个数x,y表示一对询问。
 
 

Output

 

共M行,第i行一个正整数表示第i个询问的结果。

Sample Input

3 3
1 4 3
0 1
0 1
4 3


Sample Output

5
7
7

HINT

 



HINT

N=12000,M=6000,x,y,Ai在signed longint范围内。

 

Source

【分析】
第一次写可持久化trie,还有点问题。
题解网上都是...先不说了
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <vector>
  6 #include <utility>
  7 #include <iomanip>
  8 #include <string>
  9 #include <cmath>
 10 #include <queue>
 11 #include <assert.h>
 12 #include <map>
 13 
 14 const int N = 12000 + 10;
 15 const int SIZE = 111;//块状链表的根号50000 
 16 const int M = 50000 + 5;
 17 using namespace std;
 18 typedef long long ll;
 19 struct Node{
 20        int val;//代表数量
 21        int num;//代表值
 22        Node *ch[2]; 
 23 }mem[N * 31 * 10], *root[N];
 24 int n, m;//n为数量,m为操作次数 
 25 struct BLOCK_LIST{//块状链表 
 26        int data[SIZE];
 27        int size, next;
 28        void init(){
 29             size = 0;
 30             memset(data, 0, sizeof(data));
 31             next = -1;
 32        }
 33 }list[SIZE];
 34 int tot = 0;//记录mem使用空间 
 35 int Max[SIZE + 10][SIZE + 10], Pos;//表示从i到j块的最大异或值 
 36 int data[N];
 37 
 38 Node *NEW(){//创建新trie节点
 39      Node *p = &mem[tot++];
 40      p->val = p->num = 0;
 41      p->ch[0] = p->ch[1] = NULL;
 42      return p; 
 43 }
 44 void insert(Node *&p, Node *&last, int x){//k为根 
 45      p = NEW();
 46      
 47      Node *u = p, *a = last;
 48      for (int i = 30; i >= 0 ; i--){
 49          int t = (((1 << i) & x) == 0 ? 0 : 1);
 50          if (u->ch[t] == NULL){
 51             u->ch[t] = NEW();
 52             u->ch[t]->val = t;
 53             u->ch[t]->num = a->ch[t]->num + 1;
 54          }
 55          u->ch[t ^ 1] = a -> ch[t ^ 1];
 56          u = u -> ch[t];
 57          a = a -> ch[t];
 58      }
 59      return;
 60 }
 61 int find(Node *&a, Node *&b, int val){
 62     int Ans = 0;
 63     Node *x = a, *y = b; 
 64     for (int i = 30; i >= 0; i--){
 65         
 66         int t = ((((1 << i) & val) == 0 ? 0 : 1) ^ 1);
 67         if (x->ch[t] == NULL || (x->ch[t]->num - y->ch[t]->num) <= 0) t = (t ^ 1);
 68         Ans += (1 << i) * t;
 69         x = x->ch[t];
 70         y = y->ch[t];
 71     }
 72     //Ans += t;
 73     return Ans;
 74 }
 75 
 76 void prepare(){
 77      memset(Max, 0, sizeof( Max ));
 78      Pos = 0;//Pos为块状链表的标号
 79      list[Pos++].init();
 80      insert(root[1], root[0], 0);//插入可持久化trie
 81      for (int cur = 0, i = 1; i <= n; cur = list[cur].next){
 82          int j, M = 0;//M用来记录块的最大值 
 83          for (j = 0; j < SIZE && i <= n; i++, j++){
 84              list[cur].data[j] = data[i];
 85              list[cur].size++;
 86              insert(root[i + 1], root[i], data[i]);//插入可持久化trie
 87              int M2 = data[i];
 88              //M2 = find(root[i + 1], root[cur * SIZE], list[cur].data[j]); 
 89              //printf("%d\n", M2);
 90              //if (M2 == data[i]) M2 = 0;//显然如果是它自己不如不加即直接从开头一直异或到i
 91              //Max[cur][cur] = M2;
 92              for (int k = Pos - 1; k >= 0; k--){
 93                  int tmp = find(root[i + 1], root[k * SIZE], data[i]);
 94                  //if (tmp == data[i]) tmp = 0;
 95                  if ((M2 ^ data[i]) < (tmp ^ data[i])) M2 = tmp;
 96                  Max[k][cur] = max(Max[k][cur], M2 ^ data[i]);//顺便利用O(sqrt(n))的时间预处理出Max数组 
 97              }
 98          }
 99          //创建新块
100          if (j == SIZE){
101             list[Pos].init();
102             list[cur].next = Pos++;
103          }
104      } 
105      //printf("%d\n", root[1]->ch[0]->ch[1]->num);
106 }
107 int query(int l, int r){
108      int x = (l - 1) / SIZE, y = (r - 1) / SIZE;//x代表l和r所代表的块
109      int Ans = 0;
110      if (x == y){
111            for (int i = l; i <= r; i++)
112                Ans = max(Ans, find(root[r + 1], root[l - 1], data[i]) ^ data[i]);
113            return Ans;
114      }else{
115            if (x  <= y - 1) Ans = Max[x ][y - 1];
116            //for (int i = r; i >= l; i--) if ((data[i] ^ data[i - 1]) == 32767) printf("fuck");
117            for (int i = l; i <= ((x + 1) * SIZE) && i <= n; i++) Ans = max(Ans, find(root[r + 1], root[l - 1], data[i]) ^ data[i]);
118            for (int i = r; i > y * SIZE; i--) Ans = max(Ans, find(root[r + 1], root[l - 1], data[i]) ^ data[i]);
119            return Ans;
120            //for (int i = l; i <= r; i++)
121            //    Ans = max(Ans, find(root[r + 1], root[l - 1], data[i]) ^ data[i]);
122            //return Ans;
123      }
124 }
125 //处理询问
126 void work(){
127      int last_ans = 0;
128      for (int i = 1; i <= m; i++){
129          int x, y, l, r;
130          scanf("%d%d", &l, &r);
131          //l--;
132          //l = min(((ll)((ll)x + (ll)last_ans) % n) + 1 , ((ll)((ll)y + (ll)last_ans) % n)+ 1);
133          //r = max(((ll)((ll)x + (ll)last_ans) % n) + 1 , ((ll)((ll)y + (ll)last_ans) % n)+ 1);
134          last_ans = query(l, r);
135          printf("%d\n", last_ans);
136      } 
137 }
138 //单纯的插入一个数 
139 void build(Node *&b, int x){
140      Node *u = b;
141      for (int i = 30; i >= 0; i--){
142          int t = (((1 << i) & x) == 0 ? 0 : 1);//表示这一位是否是0
143          if (u->ch[t] == NULL){
144             u->ch[t] = NEW();
145             u->ch[t]->val = t;
146             u->ch[t]->num = 0;//注意,这里仅仅只是建树,所以不能改数字 
147          } 
148          u = u->ch[t]; 
149      } 
150      return;
151 } 
152 void init(){
153      //读入+建初始树 
154      scanf("%d%d", &n, &m);
155      for (int i = 0; i < N; i++) root[i] = NULL;
156      root[0] = NEW();
157      data[0] = 0;
158      for (int i = 1; i <= n; i++){
159          scanf("%d", &data[i]);
160          data[i] = data[i] ^ data[i - 1];
161          build(root[0], data[i]);
162          //printf("%d\n", data[i]);
163      }
164      build(root[0], 0);//记得加0 
165      //printf("%d", root[0]->val);
166 }
167 void debug(){
168      insert(root[1], root[0], 0);
169      insert(root[2], root[1], 1);
170      insert(root[3], root[2], 6);
171      printf("%d\n", find(root[3], root[1], 6));
172 }
173 
174 int main(){
175     #ifdef LOCAL
176     freopen("data.txt",  "r",  stdin);
177     freopen("out.txt",  "w",  stdout); 
178     #endif
179     init();
180     prepare();
181     work();
182     printf("%d\n", tot);
183     //debug();
184     return 0;
185 }
View Code

 

posted @ 2015-03-09 22:49  TCtower  阅读(431)  评论(0编辑  收藏  举报