题目

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。

输入格式

第一行两个整数N和M。

第二行有N个正整数,其中第i个数为Ai,有多余空格。

后M行每行两个数x,y表示一对询问。

输出格式

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

输入样例

3 3

1 4 3

0 1

0 1

4 3

输出样例

5

7

7

提示

HINT

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

题解

区间异或和最大,转化为两个前缀和

多次询问不同区间,用可持久化trie树

但每次要任意选出两个数,而常规的trie树只支持一个数询问区间和它的最大异或值,不能处理区间内任意两个数异或和最大值

何破?

我们不可能每次询问\(O(n^2logn)\)枚举其中一个数

那就预处理!

如果我们能预处理出每个区间异或最大值,就是\(O(n^2logn)\)预处理,\(O(1)\)查询

能不能均摊一下?

分块!

我们只预处理每个块头到其后面所有位置的数异或的最大值

具体的,设\(f[i][j]\)表示\(i\)块开头位置到\(j\)中所有数异或的最大值,记块头为\(u\),则\(f[i][j]\)即为区间\([u,j]\)的答案

算出\(f[i][j]\)只需要枚举每个\(j\)就可以了

具体地,\(f[i][j] = max(f[i][j - 1],query(j,区间[u,j - 1]))\)

那么每次询问的时候,对于\(l\)之后的第一个块头\(u\),可以得到出后面的答案\(f[u][r]\)

所以我们只需要计算区间\([l,u - 1]\)的数与其后面的数的最大异或值

这个区间大小不会超过\(\sqrt{n}\),所以可以直接统计

总的复杂度\(O(n\sqrt{n}logn)\)

【坑点,给出的x,y可能超过int范围】

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define LL long long int
using namespace std;
const int maxn = 12005,Bit = 31,maxm = 6000000,INF = 100000000;
inline LL read(){
LL out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
LL n,m,A[maxn],sum[maxn],bin[40];
LL f[200][maxn],block[maxn],B,lans;
struct trie{
int ch[maxm][2],sum[maxm],rt[maxn],cnt;
int ins(int pre,int x){
int tmp,u;
tmp = u = ++cnt;
for (int i = Bit; i >= 0; i--){
ch[u][0] = ch[pre][0];
ch[u][1] = ch[pre][1];
sum[u] = sum[pre] + 1;
LL t = x & bin[i]; t >>= i;
pre = ch[pre][t];
u = ch[u][t] = ++cnt;
}
sum[u] = sum[pre] + 1;
return tmp;
}
LL query(int u,int v,int x,int dep){
if (dep < 0) return 0;
LL t = x & bin[dep]; t >>= dep;
if (sum[ch[u][t ^ 1]] - sum[ch[v][t ^ 1]])
return bin[dep] + query(ch[u][t ^ 1],ch[v][t ^ 1],x,dep - 1);
return query(ch[u][t],ch[v][t],x,dep - 1);
}
}T;
int main(){
bin[0] = 1; for (int i = 1; i <= Bit; i++) bin[i] = bin[i - 1] << 1;
n = read(); m = read(); B = (int)sqrt(n) + 1;
n++;
for (int i = 2; i <= n; i++) A[i] = read();
for (int i = 1; i <= n; i++){
sum[i] = sum[i - 1] ^ A[i];
T.rt[i] = T.ins(T.rt[i - 1],sum[i]);
block[i] = i / B;
}
for (int i = 1; i <= n; i++){
if (i == 1 || block[i] != block[i - 1]){
int b = block[i];
for (int j = i; j <= n; j++){
f[b][j] = max(f[b][j - 1],T.query(T.rt[j - 1],T.rt[i - 1],sum[j],Bit));
}
}
}
n--;
LL l,r,x,y;
while (m--){
x = read(); y = read();
l = min (((x + lans) % n) + 1, ((y + lans) % n) + 1);
r = max (((x + lans) % n) + 1, ((y + lans) % n) + 1) + 1;
lans = 0;
if (block[l] != block[r]) lans = f[block[l] + 1][r];
for (int i = l; block[i] == block[l] && i < r; i++){
lans = max(lans,T.query(T.rt[r],T.rt[i],sum[i],Bit));
}
printf("%lld\n",lans);
}
return 0;
}

BZOJ2741 【FOTILE模拟赛】L 【可持久化trie + 分块】的更多相关文章

  1. 【bzoj2741】[FOTILE模拟赛]L 可持久化Trie树+分块

    题目描述 FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor A ...

  2. BZOJ2741 FOTILE模拟赛L(分块+可持久化trie)

    显然做个前缀和之后变成询问区间内两个数异或最大值. 一种暴力做法是建好可持久化trie后直接枚举其中一个数查询,复杂度O(nmlogv). 观察到数据范围很微妙.考虑瞎分块. 设f[i][j]为第i个 ...

  3. BZOJ2741:[FOTILE模拟赛]L

    Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 .. ...

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

    Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 .. ...

  5. BZOJ.2741.[FOTILE模拟赛]L(分块 可持久化Trie)

    题目链接 首先记\(sum\)为前缀异或和,那么区间\(s[l,r]=sum[l-1]^{\wedge}sum[r]\).即一个区间异或和可以转为求两个数的异或和. 那么对\([l,r]\)的询问即求 ...

  6. BZOJ 2741: 【FOTILE模拟赛】L(可持久化Trie+分块)

    传送门 解题思路 首先求出前缀异或和,那么问题就转化成了区间内选两个数使得其异或和最大.数据范围不是很大考虑分块,设\(f[x][i]\)表示第\(x\)块开头到\(i\)这个位置与\(a[i]\)异 ...

  7. 【bzoj2741】[FOTILE模拟赛] L

    Portal --> bzoj2741 Solution 突然沉迷分块不能自拔 考虑用分块+可持久化trie来解决这个问题 对于每一块的块头\(L\),预处理\([L,i]\)区间内的所有子区间 ...

  8. bzoj 2741 [FOTILE模拟赛] L

    Description 多个询问l,r,求所有子区间异或和中最大是多少 强制在线 Solution 分块+可持久化trie 1.对于每块的左端点L,预处理出L到任意一个i,[L,j] 间所有子区间异或 ...

  9. 【BZOJ2741】【FOTILE模拟赛】L 分块+可持久化Trie树

    [BZOJ2741][FOTILE模拟赛]L Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max( ...

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

    2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1116  Solved: 292[Submit][Status] ...

随机推荐

  1. 源文件名长度大于系统支持的长度,无法删除,java主方法执行方式删除

    import java.io.File; /** * @author 海盗船长 * 2017年2月14日11:24:26 */ public class DeleteFiles { public st ...

  2. SQLServer 错误: 15404,无法获取有关 Windows NT 组/ 用户 'WIN-8IVSNAQS8T7\Administrator' 的信息,错误代码 0x534。

    在自动清理日志的作业中,执行过程出现如下问题:“SQLServer 错误: 15404,无法获取有关 Windows NT 组/ 用户 'WIN-8IVSNAQS8T7\Administrator' ...

  3. 插值(scipy.interpolate)

    https://docs.scipy.org/doc/scipy/reference/interpolate.html#module-scipy.interpolate https://stackov ...

  4. Unity之脚本编译顺序

    根据官方的解释,它们的编译顺序如下: (1)所有在Standard Assets.Pro Standard Assets或者Plugins文件夹中的脚本会产生一个Assembly-CSharp-fil ...

  5. python基础一 day10(1)

    要背的:

  6. 第1节 flume:13、14、更多flume案例一,通过拦截器实现不同类型的数据区分

    1.6.flume案例一 1. 案例场景 A.B两台日志服务机器实时生产日志主要类型为access.log.nginx.log.web.log 现在要求: 把A.B 机器中的access.log.ng ...

  7. JS任意文件转base64

    <!doctype html><html><head><meta charset="utf-8"><meta name=&qu ...

  8. sha1、base64、ase加密

    <!DOCTYPE html><html><head><title>sha1.base64.ase加密</title><meta ch ...

  9. Python使用三种方法实现PCA算法[转]

    主成分分析(PCA) vs 多元判别式分析(MDA) PCA和MDA都是线性变换的方法,二者关系密切.在PCA中,我们寻找数据集中最大化方差的成分,在MDA中,我们对类间最大散布的方向更感兴趣. 一句 ...

  10. hihoCoder-1089-Floyd

    我们读入的时候,要考虑重边的问题,我们只取边的最小值就可以了. #include <cstdio> #include <cstring> const int INF = 0x3 ...