题目描述
火星上的一条商业街里按照商店的编号1,2 ,…,n ,依次排列着n个商店。商店里出售的琳琅满目的商品中,每种商品都用一个非负整数val来标价。每个商店每天都有可能进一些新商品,其标价可能与已有商品相同。
火星人在这条商业街购物时,通常会逛这条商业街某一段路上的所有商店,譬如说商店编号在区间[L,R]中的商店,从中挑选1件自己最喜欢的商品。每个火星人对商品的喜好标准各不相同。通常每个火星人都有一个自己的喜好密码x。对每种标价为val的商品,喜好密码为x的火星人对这种商品的喜好程度与val异或x的值成正比。也就是说,val xor x的值越大,他就越喜欢该商品。每个火星人的购物卡在所有商店中只能购买最近d天内(含当天)进货的商品。另外,每个商店都有一种特殊商品不受进货日期限制,每位火星人在任何时刻都可以选择该特殊商品。每个商店中每种商品都能保证供应,不存在商品缺货的问题。
对于给定的按时间顺序排列的事件,计算每个购物的火星人的在本次购物活动中最喜欢的商品,即输出val xor x的最大值。这里所说的按时间顺序排列的事件是指以下2种事件:
事件0,用三个整数0,s,v,表示编号为s的商店在当日新进一种标价为v 的商品。
事件1,用5个整数1,L,R,x,d,表示一位火星人当日在编号为L到R的商店购买d天内的商品,该火星人的喜好密码为x。
输入输出格式
输入格式:
第1行中给出2个正整数n,m,分别表示商店总数和事件总数。
第2行中有n个整数,第i个整数表示商店i的特殊商品标价。
接下来的m行,每行表示1个事件。每天的事件按照先事件0,后事件1的顺序排列。
输出格式:
将计算出的每个事件1的val xor x的最大值依次输出。
输入输出样例
输入样例#1:
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
输出样例#1:
5
0
2
5
说明
n, m <= 100000
数据中,价格不大于100000
题解
线段树分治
线段树分治可以用来处理类似树套树的问题
但是它可以通过分治来忽视掉删除的操作
就是每次把每个询问都放进线段树的区间
然后再对修改操作进行分治
对于这道题就是把操作先都离线下来
然后按时间分治
先把所有的询问放进线段树的对应区间
然后再对所有的修改二分
在每个线段树的区间先把属于这个区间的修改做完再用01trie更新属于这个区间的查询就好了
代码
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define ls (now << 1)
# define rs (now << 1 | 1)
const int M = 100005 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
int n , m , Base = 17 , Day ;
int cnt , rt[M] , Ans[M] , Top , st[M] ;
vector < int > Seg[M << 2] ;
struct Sell { int s , v , t ; } q[M] , t1[M] , t2[M] ;
struct Q { int l , r , tl , tr , x ; } p[M] ;
struct Node { int son[2] , size ; } t[M << 5] ;
inline bool operator < (Sell a , Sell b) { return a.s < b.s ; }
struct Trie01 {
int tot ;
void Insert(int x , int k , int pre , int &now) {
t[++tot] = t[pre] ; now = tot ; t[now].size ++ ;
if(k < 0) return ; bool w = x & (1 << k) ;
Insert(x , k - 1 , t[pre].son[w] , t[now].son[w]) ;
}
int query(int l , int r , int x , int k) {
if(k < 0) return 0 ; bool w = x & (1 << k) ;
if(t[t[r].son[w ^ 1]].size - t[t[l].son[w ^ 1]].size > 0)
return query(t[l].son[w ^ 1] , t[r].son[w ^ 1] , x , k - 1) + (1 << k) ;
else return query(t[l].son[w] , t[r].son[w] , x , k - 1) ;
}
} Trie ;
void pushdown(int L , int R , int id , int l , int r , int now) {
if(l > R || r < L) return ;
if(l >= L && r <= R) { Seg[now].push_back(id) ; return ; }
int mid = (l + r) >> 1 ;
if(mid >= R) pushdown(L , R , id , l , mid , ls) ;
else if(mid < L) pushdown(L , R , id , mid + 1 , r , rs) ;
else {
pushdown(L , mid , id , l , mid , ls) ;
pushdown(mid + 1 , R , id , mid + 1 , r , rs) ;
}
}
inline int Find(int x) {
int l = 1 , r = Top , ret = 0 ;
while(l <= r) {
int mid = (l + r) >> 1 ;
if(st[mid] <= x) ret = mid , l = mid + 1 ;
else r = mid - 1 ;
}
return ret ;
}
inline void Update(int L , int R , int now) {
Top = 0 ; Trie.tot = 0 ;
for(int i = L ; i <= R ; i ++) {
st[++Top] = q[i].s ;
Trie.Insert(q[i].v , Base , rt[Top - 1] , rt[Top]) ;
}
for(int i = 0 , k , l , r ; i < Seg[now].size() ; i ++) {
k = Seg[now][i] ;
l = Find(p[k].l - 1) , r = Find(p[k].r) ;
Ans[k] = max(Ans[k] , Trie.query(rt[l] , rt[r] , p[k].x , Base)) ;
}
}
void Solve(int L , int R , int l , int r , int now) {
if(R < L) return ;
int mid = (l + r) >> 1 , a = 0 , b = 0 ;
Update(L , R , now) ; if(l == r) return ;
for(int i = L ; i <= R ; i ++)
if(q[i].t <= mid) t1[++a] = q[i] ;
else t2[++b] = q[i] ;
for(int i = 1 ; i <= a ; i ++) q[L + i - 1] = t1[i] ;
for(int i = 1 ; i <= b ; i ++) q[L + a + i - 1] = t2[i] ;
Solve(L , L + a - 1 , l , mid , ls) ;
Solve(L + a , R , mid + 1 , r , rs) ;
}
int main() {
n = read() ; m = read() ;
for(int i = 1 , x ; i <= n ; i ++) {
x = read() ;
Trie.Insert(x , Base , rt[i - 1] , rt[i]) ;
}
int opt , l , r , s , v , x , d ;
for(int i = 1 ; i <= m ; i ++) {
opt = read() ;
if(opt == 0) {
s = read() , v = read() ; ++ Day ;
q[Day] = (Sell) { s , v , Day } ;
}
else {
l = read() , r = read() , x = read() , d = read() ;
p[++cnt] = (Q) { l , r , max(1 , Day - d + 1) , Day , x } ;
Ans[cnt] = Trie.query(rt[l - 1] , rt[r] , x , Base) ;
}
}
for(int i = 1 ; i <= cnt ; i ++) pushdown(p[i].tl , p[i].tr , i , 1 , Day , 1) ;
sort(q + 1 , q + Day + 1) ;
Solve(1 , Day , 1 , Day , 1) ;
for(int i = 1 ; i <= cnt ; i ++) printf("%d
",Ans[i]) ;
return 0 ;
}