[FJOI2015]火星商店问题

题目描述

火星上的一条商业街里按照商店的编号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\n",Ans[i]) ;
	return 0 ;
}
posted @ 2018-12-13 07:52  beretty  阅读(369)  评论(1编辑  收藏  举报