标签:
题意:给定一个长度为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 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啊.............然后查题解..................发现是分块= =....什么鬼................
标签:
原文地址:http://www.cnblogs.com/iwtwiioi/p/4265371.html