zoukankan      html  css  js  c++  java
  • 「SCOI2016」美味

    「SCOI2016」美味

    题目描述

    一家餐厅有 (n) 道菜,编号 (1 ldots n) ,大家对第 (i) 道菜的评价值为 (a_i :( 1 leq i leq n ))。有 (m) 位顾客,第 (i) 位顾客的期望值为 (b_i),而他的偏好值为 (x_i)。因此,第 (i) 位顾客认为第 (j) 道菜的美味度为 (b_i ext{xor} (a_j+x_i)) (( ext{xor}) 表示异或运算)。 第 (i) 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 (l_i) 道到第 (r_i) 道中选择。请你帮助他们找出最美味的菜。

    解题思路 :

    问题要求从区间里找一个数 (a_j) ,使得 ((a_j + x_i) ext{ xor } b_i) 最大,先考虑当 (x_i = 0) 的时候是一个经典问题该怎么做

    (x_i = 0) 时显然直接用一个可持久化 (Trie) 树按位维护区间内所有 (a_j) 查询即可

    但是有加上 (x_i) 的操作由于 (Trie) 的局限性就不那么可做了,不妨考虑上述算法的本质

    (Trie) 树从高到低走的每一位本质上是对最终选的数的可行区间不断减少

    设当前第 (i) 位的大小是 (2^i) ,那么如果选了它答案一定 $ geq 2^i$ ,否则答案一定 (< 2 ^i) ,因为有 (sum_{j=0}^{i-1} 2^j =2^i - 1)

    所以我们可以用一个线段树维护 ([0, 2^{lim-1}]) 的权值来代替原本的 (Trie),每次走左儿子本质上是这一位选了 (0),走右儿子本质上是选了 (1)

    考虑查询加上 (x_i) 后的 (a_j) 本质上是将原来的 (a_j - x_i) 代替新的 (a_j) ,只需要查询的区间更改一下就可以了

    因为要回答区间的答案,所以还要把线段树可持久化一下,每次查询从高到低枚举 (b_i) 的每一位看看能否选相反的即可


    
    
    /*program by mangoyang*/
    #include<bits/stdc++.h>
    #define inf (0x7f7f7f7f)
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    typedef long long ll;
    using namespace std;
    template <class T>
    inline void read(T &x){
        int f = 0, ch = 0; x = 0;
        for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
        for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
        if(f) x = -x;
    }
    
    const int N = 1000005, len = (1 << 19) - 1;
    int rt[N], n, m;
    
    struct SegmentTree{
    	int sz[N*25], lc[N*25], rc[N*25], size;
    	inline void ins(int &u, int pr, int l, int r, int pos){
    		u = ++size;
    		lc[u] = lc[pr], rc[u] = rc[pr], sz[u] = sz[pr] + 1;
    		if(l == r) return;
    		int mid = l + r >> 1;
    		if(pos <= mid) ins(lc[u], lc[pr], l, mid, pos);
    		else ins(rc[u], rc[pr], mid + 1, r, pos);
    	}
    	inline int query(int x, int y, int l, int r, int L, int R){
    		if(l >= L && r <= R) return (sz[y] - sz[x] > 0);
    		int mid = l + r >> 1, res = 0;
    		if(L <= mid) res |= query(lc[x], lc[y], l, mid, L, R);
    		if(mid < R) res |= query(rc[x], rc[y], mid + 1, r, L, R);
    		return res;
    	}
    }van;
    
    int main(){
    	read(n), read(m);
    	for(int i = 1, x; i <= n; i++) 
    		read(x), van.ins(rt[i], rt[i-1], 0, len, x);
    		
    	while(m--){
    		int now, add, l = 0, r = len, res = 0, L, R;
    		read(now), read(add), read(L), read(R);
    		for(int i = 18; ~i; i--){
    			int s = ((now >> i) & 1) ^ 1, mid = l + r >> 1;
    			int nl = s ? mid + 1 : l, nr = s ? r : mid;
    			if(van.query(rt[L-1], rt[R], 0, len, Max(nl - add, 0), Max(nr - add, 0)))
    				res |= 1 << i, l = nl, r = nr;
    			else l = s ? l : mid + 1, r = s ? mid : r;
    		}
    		printf("%d
    ", res);
    	}		
    	return 0;		
    }
    
    
  • 相关阅读:
    MyEclipse中的Tomcat跑大项目时内存溢出:permgen space
    MyEclipse新建工作空间后的配置详细步骤
    解决eclipse复制粘贴js代码卡死的问题
    eclipse复制工作空间配置
    maven项目检出后报错(包括编译报错和运行报错)的常见检查处理方式
    MyEclipse中引用的maven配置文件只访问私服的配置
    图标网站
    afasf
    一个权限管理模块的设计(转载)
    奇艺下载
  • 原文地址:https://www.cnblogs.com/mangoyang/p/9490450.html
Copyright © 2011-2022 走看看