zoukankan      html  css  js  c++  java
  • [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
    ",Ans[i]) ;
    	return 0 ;
    }
    
  • 相关阅读:
    从程序员到项目经理(1)
    从程序员到项目经理(26):项目管理不能浑水摸鱼
    职场“常青树”越老越值钱
    阿里巴巴离职DBA 35岁总结的职业生涯
    CEPH RGW多 ZONE的配置
    CEPH 对象存储的系统池介绍
    Windows 下配置 Vagrant 环境
    vagrant 创建虚拟机时遇到问题
    浅谈Ceph纠删码
    磁盘缓存
  • 原文地址:https://www.cnblogs.com/beretty/p/10112004.html
Copyright © 2011-2022 走看看