# 分治技巧在高级数据结构中的应用——线段树分治（二）

## 4137: [FJOI2015]火星商店问题

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 210  Solved: 98
[Submit][Status][Discuss]

4 6
1 2 3 4
1 1 4 1 0
0 1 4
0 1 3
1 1 1 1 0
1 1 1 1 1
1 1 2 1 2

5
0
2
5

n, m <= 100000

## Source

void Seg_Dived(int ml, int mr, int tl, int tr, int at) { //ml，mr表示修改操作区间，tl，tr表示二分的时间区间
dt = 0; int mid = tl + tr >> 1; //二分时间区间
for(int i = 1;i <= at; ++i) //添加可询问区间进入队列
if(q[id[i]].st <= tl && tr <= q[id[i]].ed)
d[++dt] = id[i];
work(ml, mr); //解决询问
int lt = 0, rt = 0;
for(int i = ml;i <= mr; ++i) { //分治修改区间
if(mod[i].tim <= mid)
tmpL[lt++] = mod[i];
else tmpR[rt++] = mod[i];
}
for(int i = 0;i < lt; ++i) mod[i + ml] = tmpL[i];
for(int i = 0; i < rt; ++i) mod[i + ml + lt] = tmpR[i];
if(tl == tr) return;
int idt = 0;
for(int i = 1;i <= at; ++i) { //把有关[L，mid]区间的询问加入队列
if(q[id[i]].st <= tl && tr <= q[id[i]].ed) continue;
if(q[id[i]].st <= mid) swap(id[i], id[++idt]);
}
Seg_Dived(ml, ml + lt - 1, tl, mid, idt); //分治左区间
idt = 0;
for(int i = 1;i <= at; ++i) { //把有关[mid + 1，R]区间的询问加入队列
if(q[id[i]].st <= tl && tr <= q[id[i]].ed) continue;
if(q[id[i]].ed > mid) swap(id[i], id[++idt]);
}
Seg_Dived(ml + lt, mr, mid + 1, tr, idt); //分治右区间
}

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
const int N = 1e5;
const int T = 5e6;
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) - '0' + ch; ch = getchar();}
return x * f;
}
struct ask {int l, r, st, ed, x;}q[N];
struct modify {int shop, tim, val;}mod[N], tmpL[N], tmpR[N];
bool cmp(modify a, modify b) {return a.shop < b.shop;}
int sz, sum[T], ch[T][2], bin[30], num[N], root[N], nt, dt, d[N], ans[N], id[N];

void add(int &cur, int last, int val) {
cur = sz + 1; bool d;
for(int i = 17; ~i; --i) {
sum[++sz] = sum[last] + 1;
d = bin[i] & val;
ch[sz][!d] = ch[last][!d];
ch[sz][d] = sz + 1;
last = ch[last][d];
}
sum[++sz] = sum[last] + 1;
}

int query(int lt, int rt, int val) {
if(lt > rt) return 0;
int ans = 0;
for(int i = 17; ~i; --i) {
bool d = bin[i] & val;
if(sum[ch[rt][!d]] - sum[ch[lt][!d]]) {
ans |= bin[i];
rt = ch[rt][!d];
lt = ch[lt][!d];
}
else {
rt = ch[rt][d];
lt = ch[lt][d];
}
}
return ans;
}

int Lower(int val) {
int l = 1, r = nt, ret = 0;
while(l <= r) {
int mid = l + r >> 1;
if(num[mid] <= val) {
ret = mid;
l = mid + 1;
}
else r = mid - 1;
}
return ret;
}

void work(int ml, int mr) {
sz = 0; nt = 0;
for(int i = ml; i <= mr; ++i) {
++nt;
num[nt] = mod[i].shop;
}
for(int i = 1;i <= dt; ++i) {
int l = Lower(q[d[i]].l - 1);
int r = Lower(q[d[i]].r);
ans[d[i]] = max(ans[d[i]], query(root[l], root[r], q[d[i]].x));
}
}

void Seg_Dived(int ml, int mr, int tl, int tr, int at) {
if(ml > mr || at == 0) return;
dt = 0; int mid = tl + tr >> 1;
for(int i = 1;i <= at; ++i)
if(q[id[i]].st <= tl && tr <= q[id[i]].ed)
d[++dt] = id[i];
work(ml, mr); int lt = 0, rt = 0;
for(int i = ml;i <= mr; ++i) {
if(mod[i].tim <= mid)
tmpL[lt++] = mod[i];
else tmpR[rt++] = mod[i];
}
for(int i = 0;i < lt; ++i) mod[i + ml] = tmpL[i];
for(int i = 0; i < rt; ++i) mod[i + ml + lt] = tmpR[i];
if(tl == tr) return;
int idt = 0;
for(int i = 1;i <= at; ++i) {
if(q[id[i]].st <= tl && tr <= q[id[i]].ed) continue;
if(q[id[i]].st <= mid) swap(id[i], id[++idt]);
}
Seg_Dived(ml, ml + lt - 1, tl, mid, idt);
idt = 0;
for(int i = 1;i <= at; ++i) {
if(q[id[i]].st <= tl && tr <= q[id[i]].ed) continue;
if(q[id[i]].ed > mid) swap(id[i], id[++idt]);
}
Seg_Dived(ml + lt, mr, mid + 1, tr, idt);
}

int main() {
bin[0] = 1; for(int i = 1;i <= 20; ++i) bin[i] = bin[i - 1] << 1;
int n = read(), m = read(), day = 0, mt = 0, qt = 0, cur = 0;
for(int i = 1;i <= n; ++i) add(root[i], root[i - 1], read());
for(int i = 1;i <= m; ++i) {
if(!opt) {
mod[mt].val = read(); mod[mt].tim = day;
}
else {
q[qt].st = max(day - d, 0) + 1; q[qt].ed = day;
ans[qt] = query(root[q[qt].l - 1], root[q[qt].r], q[qt].x);
}
}
sort(mod + 1, mod + mt + 1, cmp);
for(int i = 1;i <= qt; ++i) id[i] = i;
Seg_Dived(1, mt, 1, day, qt);
for(int i = 1;i <= qt; ++i) printf("%d\n", ans[i]);
return 0;
}