【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

 

你可能感兴趣的:(trie)