题意:给定一个长度为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范围内)

#include <bits/stdc++.h>
using namespace std; const int nT=5000005, N=12005;
struct node *null;
struct node {
node *c[2];
int s;
}pool[nT], *it=pool;
node *newT() { node *x; x=it++; x->c[0]=x->c[1]=null; x->s=0; return x; }
node *add(node *p, int y, int dep=30) {
node *x=newT();
if(dep==-1) return x;
*x=*p;
int f=(y>>dep)&1;
x->c[f]=add(p->c[f], y, dep-1); ++x->c[f]->s;
return x;
}
int query(node *a, node *b, int k, int dep=30) {
if(dep==-1) return 0;
int f=(k>>dep)&1, ff=f^1;
if(b->c[ff]->s>a->c[ff]->s) return (1<<dep)|query(a->c[ff], b->c[ff], k, dep-1);
return query(a->c[f], b->c[f], k, dep-1);
}
node *Root[N], **root=Root+1;
int a[N], n, m, size, num, pos[N], d[120][N], last; void init() {
null=new node; null->c[0]=null->c[1]=null; null->s=0;
root[0]=null;
root[-1]=null; scanf("%d%d", &n, &m); //++n;
for(int i=1; i<=n; ++i) scanf("%d", &a[i]), a[i]^=a[i-1];
for(int i=1; i<=n; ++i) root[i]=add(root[i-1], a[i]);
size=sqrt(n+0.5);
num=(n-1)/size+1;
for(int i=1; i<=n; ++i) pos[i]=(i-1)/size+1;
for(int i=1; i<=num; ++i) {
int pi=(i-1)*size+1;
for(int j=pi; j<=n; ++j) d[i][j]=max(d[i][j-1], query(root[pi-1], root[j], a[j]));
}
}
int getans(int l, int r) {
--l;
int bl=pos[l], ret=0;
if(pos[r]>bl) ret=d[bl+1][r];
for(int i=l, end=min(r, bl*size); i<=end; ++i) ret=max(ret, query(root[l-1], root[r], a[i]));
return ret;
}
void solve() {
int x, y, l, r;
while(m--) {
scanf("%d%d", &x, &y);
x=(((long long)last+x)%n)+1;
y=(((long long)last+y)%n)+1;
l=min(x, y); r=max(x, y); //printf("%d %d\n", l, r);
printf("%d\n", last=getans(l, r));
}
}
int main() {
init();
solve();
return 0;
}

  

(自己的傻×做法,线段树套可持久化trie,mle成翔)

#include <bits/stdc++.h>
using namespace std; typedef long long ll;
const int M=8000005;
struct node *null;
struct node {
node *l, *r;
int cnt;
}pool[M], *bin[M], *it=pool, *nod;
int top;
node *newnode() {
node *x;
if(!top) { if(pool+M==it) exit(0); x=it++; }
else x=bin[--top];
x->l=x->r=null; x->cnt=1;
return x;
}
void clean(node *&x) {
if(x!=null && x!=nod && !(--x->cnt)) { bin[top++]=x; clean(x->l); clean(x->r); }
x=null;
}
node *merge(node *a, node *b) {
if(a==null) { ++b->cnt; return b; }
if(b==null) { ++a->cnt; return a; }
node *x=newnode();
x->l=merge(a->l, b->l);
x->r=merge(a->r, b->r);
return x;
}
node *add(node *p, ll y, int dep) {
if(dep==-1) return nod;
node *x=newnode();
x->l=p->l;
x->r=p->r;
if((y>>dep)&1) ++x->l->cnt, x->r=add(p->r, y, dep-1);
else ++x->r->cnt, x->l=add(p->l, y, dep-1);
return x;
}
node *add(node *p, ll y) { node *x=add(p, y, 63); clean(p); return x; }
node *build(node *a, node *b) {
if(a==null || b==null) return null;
node *x=newnode();
if(b->l!=null) {
x->l=build(a->l, b->l);
x->r=build(a->r, b->l);
}
if(b->r!=null) {
node *t;
x->l=merge(t=x->l, build(a->r, b->r)); clean(t);
x->r=merge(t=x->r, build(a->l, b->r)); clean(t);
}
return x;
}
void P(node *x, ll now, int dep=63) {
if(x==null) return;
if(dep==-1) printf("now:%lld\n", now);
P(x->l, now, dep-1);
P(x->r, now|(1<<dep), dep-1);
}
void D(node *x) {
P(x, 0); puts("");
} struct T {
node *l, *r, *all;
ll sum;
void pushup(T &lc, T &rc) {
sum=lc.sum^rc.sum;
static node *t;
l=merge(lc.l, build(rc.l, add(null, lc.sum)));
r=merge(rc.r, build(lc.r, add(null, rc.sum)));
all=merge(lc.all, rc.all); // printf("top:%d\n", top);
all=merge(t=all, build(lc.r, rc.l)); clean(t); // printf("sum:%lld , have:\n", sum); D(all);
}
ll get(node *x, int dep, bool flag) {
if(dep==-1) return 0;
ll ret=0;
if(x->l!=null && x->r!=null)
if(flag) ret=get(x->l, dep-1, 0);
else ret=(1ll<<dep), ret|=get(x->r, dep-1, 0);
else if(x->l==null && x->r!=null)
ret=(1ll<<dep), ret|=get(x->r, dep-1, 0);
else if(x->r==null && x->l!=null)
ret=get(x->l, dep-1, 0);
else puts("error");
return ret;
}
ll get() { return get(all, 63, 1); }
void clr() { clean(l); clean(r); clean(all); }
T& operator=(const T &a) { l=a.l; r=a.r; all=a.r; sum=a.sum; ++l->cnt; ++r->cnt; ++all->cnt; return *this; }
}t[12005<<2]; int n, q;
ll a[12005];
void build(int l, int r, int x) {
if(l==r) {
t[x].l=t[x].r=t[x].all=add(null, a[l]); // printf("%lld\n", a[l]); D(t[x].all);
t[x].sum=a[l];
return;
}
int mid=(l+r)>>1, lc=x<<1, rc=lc|1;
build(l, mid, lc);
build(mid+1, r, rc);
t[x].pushup(t[lc], t[rc]);
}
void query(int l, int r, int x, int L, int R, T &ret) {
if(L<=l && r<=R) { ret=t[x]; return; }
int mid=(l+r)>>1;
if(R<=mid) { query(l, mid, x<<1, L, R, ret); return; }
else if(mid<L) { query(mid+1, r, x<<1|1, L, R, ret); return; }
T lc, rc;
query(l, mid, x<<1, L, R, lc);
query(mid+1, r, x<<1|1, L, R, rc);
ret.pushup(lc, rc); lc.clr(); rc.clr();
}
void init() {
null=new node; null->l=null->r=null; null->cnt=1;
nod=newnode();
}
int main() {
scanf("%d%d", &n, &q);
init();
for(int i=1; i<=n; ++i) scanf("%lld", &a[i]);
build(1, n, 1);
int last=0, x, y, l, r;
T t;
while(q--) {
scanf("%d%d", &x, &y);
x=((x+last)%n)+1;
y=((y+last)%n)+1;
l=min(x, y);
r=max(x, y); // printf("l:%d, r:%d\n", l, r);
query(1, n, 1, l, r, t);
printf("%d\n", last=t.get());
t.clr();
}
return 0;
}

  

题解:

我看到大家的tag是可持久化trie后..我就往这个方向思考了下...就yy出了第一种sb做法.......................

即:发现我们只需要维护二进制位...然后查询就是在对应区间一直向右走即可(特判符号位...),用线段树维护区间........可持久化合并trie.......可是你会发现.........有O(nlogn)次合并..每次合并O(size(trie)).................然后可能又tle又mle。反正我开了引用计数的垃圾回收也跪了...............玛雅,rewrite的节奏啊...3k啊.............然后查题解..................发现是分块= =....什么鬼................

吐槽:最近到底怎么了.....................越是放假就越颓废??我感觉一放假,什么事情都会发生= =...这几天天天家里来客人妈呀...........能不能愉快的做题了........而且由于脑袋不知怎么得..转的特别慢...脑洞到是还好..可是一些简单的东西我要想好久啊啊>_<。。。还有本题竟然没有负数.....而且在int范围内............

ydc狂D蒟蒻我TAT....我已经被D成狗了.........ydc(先发了我这篇还没写完的博文....又发了一个自己讲莫队分块的博文的链接...下边是有我20天前的脑残留言的):“我怎么感到是在羞辱我”...............................(妈呀...还是在半群里...

真正的题解:

首先转化问题(妈呀完全没想到啊...),由于xor操作有特殊的性质,即$a \otimes b \otimes b = a$所以我们要求一段区间[a,b]的xor和,可以由[0, b]和[0, a-1]的xor值得来,设$s[i]=a[1] \otimes a[2] \otimes \cdots \otimes a[i]$,那么[l, r]区间的xor和就是 $s[r] \otimes s[l-1]$

果然我是脑残吗...

然后考虑区间最大的....即我们要求区间$[l, r]$最大的xor值,就是要求

$$max\{ s[j-1] \otimes s[i], l<=j<=i<=r \}$$

转化一下,其实就是要求$[l-1, r]$这个区间取两个数$i, j$求最大的$s[j] \otimes s[i]$(可以直接忽略i=j的情况,对结果无影响...)

容易得到dp方程,设d[i, j]表示区间$[i, j]$取两个数最大的xor值

$$d[i,j]=max\{d[i,j-1], f(s[j], \{s[l-1 \cdots r] \} ) \}, f表示将s[j]放到那个集合中找到一个最大的xor和\}$$

而这个方程外层都已经是$O(n^2)$的...

先考虑决策....容易想到这是个类似trie的东西....然后自己就能yy出来可持久化trie了...trie的边就代表一个二进制位..然后从上往下走即可....请自行yy...(....可持久化用在两个地方...1、省内存...2、区间信息...

然后就是分块大法!

引用ydc:“一般莫队能做的,分块+可持久化线段树/可持久化块状链表都是能做的”,orz

我们分块处理上边的方程..先分成$\sqrt n$块..然后方程$d[i,j]$表示第$i$块的起点到第$j$个元素的最大异或值...方程转移一样...这样预处理就是$O(31*n^{1.5})$了...(31是位数别说你看不懂..即log(2^31)

然后对于连续的我们直接得到答案,最后在处理一下非连续的即可...

总复杂度

$O(31*n^{1.5})$预处理,$O(31*mn^{0.5})$查询...可以水过..

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

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

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

  2. bzoj 2741 [FOTILE模拟赛] L

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

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

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

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

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

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

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

  6. BZOJ2741:[FOTILE模拟赛]L

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

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

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

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

    可持久化Trie+分块 神题……Orz zyf & lyd 首先我们先将整个序列搞个前缀异或和,那么某一段的异或和,就变成了两个数的异或和,所以我们就将询问[某个区间中最大的区间异或和]改变成 ...

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

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

  10. BZOJ2741: 【FOTILE模拟赛】L

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

随机推荐

  1. 重温WCF之构建一个简单的WCF(一)(2)通过Windows Service寄宿服务和WCF中实现操作重载

    参考地址:http://www.cnblogs.com/zhili/p/4039111.html 一.如何在Windows Services中寄宿WCF服务 第一步:创建Windows 服务项目,具体 ...

  2. ExcelReport第二篇:ExcelReport源码解析

    导航 目   录:基于NPOI的报表引擎——ExcelReport 上一篇:使用ExcelReport导出Excel 下一篇:扩展元素格式化器 概述 针对上一篇随笔收到的反馈,在展开对ExcelRep ...

  3. gcc【数学几何】

    GCC Time Limit: 1000MS Memory limit: 65536K 题目描述 The GNU Compiler Collection (usually shortened to G ...

  4. python装饰器入门

    按别人的教程弄的. 要清楚基于类和基于函数的实现的不同之处. #!/usr/bin/env python # -*- coding: utf-8 -*- ''' class entryExit(obj ...

  5. 【20140113】package 与 import

    一个完整的java源程序应该包括下列部分: package语句: //该部分至多只有一句,必须放在源程序的第一句 import语句: public classDefinition: //公共类定义部分 ...

  6. tkprof工具详解二(一些实例)

    TKPROF是一个可执行文件,自带在Oracle Server软件中,无需额外的安装. 该工具文件可以用来解析ORACLE的SQL TRACE(10046) 以便生成更可读的内容.  实际上tkpro ...

  7. 攻城狮在路上(叁)Linux(二十三)--- linux磁盘参数修改(设备代码、设备名)

    一.mknod:设置设备代码 linux中,所有的设备都是用文件来表示,文件通过major与minor数值来判断. major为主设备代码,minor为设备代码(需要查询),示例如下: /dev/hd ...

  8. 攻城狮在路上(叁)Linux(零)--- 软件环境、参考书目等一览表

    1.参考书目:鸟哥的Linux私房菜. 2.环境: Cent_os.

  9. JDK中的设计模式

    Creational(创建模式) Abstract factory: 创建一组有关联的对象实例.这个模式在JDK中也是相当的常见,还有很多的framework例如Spring.我们很容易找到这样的实例 ...

  10. Android入门开发之SD卡读写操作(转)

    SD卡的读写是我们在开发android 应用程序过程中最常见的操作.下面介绍SD卡的读写操作方式: 1. 获取SD卡的根目录 String  sdCardRoot = Environment.getE ...