【BZOJ】【2741】【FOTILE模拟赛】L

可持久化Trie+分块



  神题……Orz zyf & lyd

  首先我们先将整个序列搞个前缀异或和,那么某一段的异或和,就变成了两个数的异或和,所以我们就将询问【某个区间中最大的区间异或和】改变成【某个区间中 max(两个数的异或和)】

  要是我们能将所有[l,r]的答案都预处理出来,那么我们就可以O(1)回答了;然而我们并不能。

  一个常见的折中方案:分块!

  这里先假设我们实现了一个神奇的函数ask(l,r,x),可以帮我们求出[l,r]这个区间中的数,与x最大的异或值。

  我们不预处理所有的左端点,我们只预处理$\sqrt{n}$个左端点,与$n$个右端点的答案。

  也就是说:将序列分成$\sqrt(n)$块,b[i][j]表示在块 i 的左端到位置 j 这个区间中,选出两个数,其最大的Xor值。

  对于询问[l,r]:设p是$l$后面第一个块的左端点,[p,r]的答案已经在b[p][r]中,[l,p]的答案就是对[l,p]中每个数x执行ask(l,r,x);

  最后:ask(l,r,x)用可持久化Trie实现:具体来说就是,如果能往1走就往1走,如果1这棵子树中所有点都是出现在$l$之前的,那么就往0走。

  可持久化Trie的写法……根据可持久化线段树的写法,yy一下试试?其实差不多= =

 1 /**************************************************************
 2     Problem: 2741
 3     User: Tunix
 4     Language: C++
 5     Result: Accepted
 6     Time:6636 ms
 7     Memory:148948 kb
 8 ****************************************************************/
 9
10 //BZOJ 2741
11 #include<cstdio>
12 #include<cmath>
13 #include<cstring>
14 #include<cstdlib>
15 #include<iostream>
16 #include<algorithm>
17 #define rep(i,n) for(int i=0;i<n;++i)
18 #define F(i,j,n) for(int i=j;i<=n;++i)
19 #define D(i,j,n) for(int i=j;i>=n;--i)
20 #define pb push_back
21 using namespace std;
22 typedef long long LL;
23 inline int getint(){
24     int r=1,v=0; char ch=getchar();
25     for(;!isdigit(ch);ch=getchar()) if (ch==‘-‘) r=-1;
26     for(; isdigit(ch);ch=getchar()) v=v*10-‘0‘+ch;
27     return r*v;
28 }
29 const int N=150010,M=5e6+10;
30 /*******************template********************/
31
32 int n,m,q,tot,rt[N],id[M],t[M][2],a[N],b[150][N];
33
34 inline void Ins(int pre,int x,int k){
35     int now=rt[k]=++tot; id[tot]=k;
36     D(i,30,0){
37         int j=(x>>i)&1;
38         t[now][j^1]=t[pre][j^1];
39         t[now][j]=++tot; id[tot]=k;
40         now=tot;
41         pre=t[pre][j];
42     }
43 }
44 inline int ask(int l,int r,int x){
45     int ans=0,now=rt[r];
46     D(i,30,0){
47         int j=((x>>i)&1)^1;
48         if (id[t[now][j]]>=l) ans|=1<<i; else j^=1;
49         now=t[now][j];
50     }
51     return ans;
52 }
53
54 int main(){
55 #ifndef ONLINE_JUDGE
56     freopen("2741.in","r",stdin);
57     freopen("2741.out","w",stdout);
58 #endif
59     n=getint(); q=getint();
60     F(i,1,n) a[i]=a[i-1]^getint();
61     id[0]=-1;
62     Ins(rt[0],a[0],0);
63     F(i,1,n) Ins(rt[i-1],a[i],i);
64     int len=sqrt(n); m=n/len+(n%len!=0);
65     rep(i,m) F(j,i*len+1,n)
66         b[i][j]=max(b[i][j-1],ask(i*len,j-1,a[j]));
67     int ans=0;
68     F(i,1,q){
69         int x=((LL)ans+(LL)getint())%n+1,y=((LL)ans+(LL)getint())%n+1;
70         if (x>y) swap(x,y);
71         x--;
72         int bx=x/len+(x%len!=0);
73         ans=bx*len < y ? b[bx][y] : 0;
74         F(j,x,min(bx*len,y))
75             ans=max(ans,ask(x,y,a[j]));
76         printf("%d\n",ans);
77     }
78     return 0;
79 }

2741: 【FOTILE模拟赛】L

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 1549  Solved: 413
[Submit][Status][Discuss]

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

By seter

[Submit][Status][Discuss]

时间: 2024-10-13 16:17:18

【BZOJ】【2741】【FOTILE模拟赛】L的相关文章

【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+last

BZOJ2741[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).

bzoj 2741: 【FOTILE模拟赛】L 分塊+可持久化trie

2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1116  Solved: 292[Submit][Status] Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y):

bzoj2741: 【FOTILE模拟赛】L

2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 2679  Solved: 766[Submit][Status][Discuss] Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一

BZOJ 2741 【FOTILE模拟赛】L(可持久化trie)

http://www.lydsy.com/JudgeOnline/problem.php?id=2741 思路:我们先将a变成a的异或前缀,这样问题就变成了,在l-1到r区间内,找出i,j令a[i]^a[j]最大. 假如i是固定的,我们可以建一个可持久化trie,在l-1到r区间内贪心寻找最优,但是这题i和j都不是固定的,如果暴力枚举i,那时间复杂度最坏是m*n*logn. 因此我们考虑这样:将n个数字分块,预处理出数组f[i][j],代表从第i块的开头作为左端点固定,j为右端点,这里面能产生的

BZOJ 2741【FOTILE模拟赛】L 分块+可持久化Trie树

题目大意 给出一个序列,求[l, r]中的最大连续xor 和. 强制在线 思路 先把整个序列分成n  √  块,预处理每一块的开头到每个数字的最大连续xor 和.这个我们只需处理出前缀xor 和,之后用可持久化Trie树就可以搞定.这样询问的右边就是整块的了.剩下左边的随便暴力一下就能过了.. CODE #define _CRT_SECURE_NO_WARNINGS #include <cmath> #include <cstdio> #include <cstring>

BZOJ 2741: 【FOTILE模拟赛】L [分块 可持久化Trie]

题意: 区间内最大连续异或和 5点调试到现在....人生无望 但总算A掉了 一开始想错可持久化trie的作用了...可持久化trie可以求一个数与一个数集的最大异或和 做法比较明显,前缀和后变成选区间内两个元素异或最大 考虑分块,预处理$f[i][j]$第i块到第j块选两个元素异或最大 询问时两边用可持久化trie暴力,中间整块已经预处理了 可以发现预处理复杂度$O(N\sqrt{N}*30)$,必须要枚举块中元素来算,不如直接保存下来$f[i][j]$为第i块到第j个元素的答案 如果说有什么教

BZOJ 2741 【FOTILE模拟赛】L 分块+可持久化Trie树

题目大意:给定一个序列,多次询问[l,r]中最大子序异或和 强制在线 一直RE的同学注意,本题的强制在线如果直接加会爆int导致调用数组下标为负 首先我们有一个转化 维护前缀异或和数组a[] 那么[l,r]中最大子序异或和就是a数组中[l-1,r]中任取两个数的最大异或值 然后分块处理 对于每块的第一个数a[i] 我们依次处理出对于所有的j>=i的[i,j]中的最大异或值 即s[i][j]=max(a[j]与i~j所有数中的最大异或值,s[i][j-1]) 然后对于每个询问[l,r],设l后面第

【BZOJ】2741: 【FOTILE模拟赛】L

题意:给定一个长度为n的序列,m次询问,每次询问一个区间[l, r],求max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r.(n<=12000, m<=6000, Ai在signed longint范围内) (自己的傻×做法,线段树套可持久化trie,mle成翔) #include <bits/stdc++.h> using namespace std; typedef long long ll; const int