【BZOJ 2741】【FOTILE模拟赛】L
2015-01-19 19:08
197 查看
2741: 【FOTILE模拟赛】L
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 1286 Solved: 332
[Submit][Status]
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 31 4 3
0 1
0 1
4 3
Sample Output
57
7
HINT
HINTN=12000,M=6000,x,y,Ai在signed longint范围内。
Source
By seter分块+可持久化trie。
根据异或的性质,我们可以预处理出前缀异或和,使问题转换为从一个区间选两个数,使其异或值最大。
Ask(l,r,s):表示在区间l-r中,找到与已知的s异或值最大的那个数。
假设已经知道Ask(l,r,s)可以在O(log(Max))时间内完成(Max是序列中的最大数),那么接下来就可以用分块来完成。
把序列分成sqrt(m)块,预处理b[i][j]表示第i块(块从0开始编号)的最左端到j(j<=n)中选两个数的最大异或值:
b[i][j]=max(b[i][j-1],Ask(i*sqrt(l),j-1,a[j])) 时间复杂度为O(sqrt(m)*n*log(Max))
然后对于每一个询问,找到在l-r区间中第一个出现的块的左端点为p,那么p-r中两个数最大的异或值已知了,只要求出l-p-1中的每一个数在l-r区间中的最大异或值即可,即Ask(l,r,a[i]) (l<=i<p)
那么Ask(l,r,s)怎么在O(log(Max))时间内完成?
用可持久化trie:
建立可持久化trie,并对每一个结点维护一个last值,表示最后是第几个数用到这个点的。
为了使异或值最大,我们尽量走与当前值相反的点(异或值为1),如果last值小于l的话,就不能走。
#include <iostream> #include <cmath> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #define M 10005 using namespace std; int t[M][2],last[M*32]={-1},rt[M],a[M],b[80][M]; int c,l,tot=0,n,m; void Insert(int root,int now,int k) { int p; rt[k]=p=++tot; last[p]=k; for (int i=30;i>=0;i--) { int j=(now>>i)&1; t[p][j^1]=t[root][j^1]; t[p][j]=++tot; p=tot,root=t[root][j]; last[p]=k; } } int Ask(int l,int r,int x) { int p=rt[r],ans=0; for (int i=30;i>=0;i--) { int j=((x>>i)&1)^1; if (last[t[p][j]]>=l) ans|=1<<i; else j^=1; p=t[p][j]; } return ans; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); a[i]^=a[i-1]; } c=(int)sqrt(m); l=n/c+(n%c!=0); Insert(rt[0],a[0],0); for (int i=1;i<=n;i++) Insert(rt[i-1],a[i],i); for (int i=0;i<c;i++) for (int j=i*l+1;j<=n;j++) b[i][j]=max(b[i][j-1],Ask(i*l,j-1,a[j])); int ans=0; while (m--) { int x,y; scanf("%d%d",&x,&y); x=(x+ans%n)%n+1,y=(y+ans%n)%n+1; if (x>y) swap(x,y); x--; int p=x/l+(x%l!=0); ans=p*l<y?b[p][y]:0; p=min(y,p*l); for (int i=x;i<=p;i++) ans=max(ans,Ask(x,y,a[i])); printf("%d\n",ans); } return 0; }
感悟:
1.RE是因为数组开小了
2.感觉可持久化数据结构都一个样啊,都是借用之前的结点,再新建logn个结点
相关文章推荐
- 【BZOJ】【2741】【FOTILE模拟赛】L
- bzoj2741【FOTILE模拟赛】L
- bzoj 2741 [FOTILE模拟赛] L
- bzoj 2741: 【FOTILE模拟赛】L 分塊+可持久化trie
- BZOJ 2741 【FOTILE模拟赛】L 分块+可持久化Trie树
- [BZOJ2741][FOTILE模拟赛]L(trie+分块)
- bzoj2741: 【FOTILE模拟赛】L 可持久化trie
- [可持久化字典树 分块] BZOJ 2741 【FOTILE模拟赛】L
- BZOJ 2741 【FOTILE模拟赛】L
- bzoj 2741: 【FOTILE模拟赛】L
- [BZOJ]2741: 【FOTILE模拟赛】L 可持久化Trie+分块
- BZOJ2741 【FOTILE模拟赛】L
- bzoj2741: 【FOTILE模拟赛】L【可持久化trie树+分块】
- 【BZOJ】2741: 【FOTILE模拟赛】L
- bzoj2741[FOTILE模拟赛L]
- bzoj2741【FOTILE模拟赛】L
- bzoj 2741: 【FOTILE模拟赛】L (分块+可持久化trie树)
- BZOJ 2741 【FOTILE模拟赛】L 可持久化Trie 分块
- BZOJ2741: 【FOTILE模拟赛】L
- BZOJ 2741 【FOTILE模拟赛】