[Luogu P3293] [BZOJ 4571] [SCOI2016]美味

8 篇文章 0 订阅
8 篇文章 0 订阅
洛谷传送门
BZOJ传送门

题目描述

一家餐厅有 n n n 道菜,编号 1... n 1...n 1...n ,大家对第 i i i 道菜的评价值为 a i ( 1 ≤ i ≤ n ) a_i(1\le i\le n) ai(1in)。有 m m m 位顾客,第 i i i 位顾客的期望值为 b i b_i bi,而他的偏好值为 x i x_i xi 。因此,第 i i i 位顾客认为第 j j j 道菜的美味度为 b i   X O R   ( a j + x i ) b_i\ XOR\ (a_j+x_i) bi XOR (aj+xi) X O R XOR XOR 表示异或运算。

i i i 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 l i l_i li 道到第 r i r_i ri 道中选择。请你帮助他们找出最美味的菜。

输入输出格式

输入格式:

1 1 1行,两个整数, n n n m m m,表示菜品数和顾客数。

2 2 2行, n n n个整数, a 1 a_1 a1 a 2 a_2 a2,…, a n a_n an,表示每道菜的评价值。

3 3 3 m + 2 m+2 m+2行,每行 4 4 4个整数, b b b x x x l l l r r r,表示该位顾客的期望值,偏好值,和可以选择菜品区间。

输出格式:

输出 m m m 行,每行 1 1 1 个整数, y m a x y_{max} ymax ,表示该位顾客选择的最美味的菜的美味值。

输入输出样例

输入样例#1:
4 4
1 2 3 4
1 4 1 4
2 3 2 3
3 2 3 3
4 1 2 4
输出样例#1:
9 
7 
6 
7

说明

对于所有测试数据, 1 ≤ n ≤ 2 ∗ 1 0 5 1\le n\le 2*10^5 1n2105 0 ≤ a i , b i , x i < 1 0 5 0\le a_i,b_i,x_i<10^5 0ai,bi,xi105 1 ≤ l i ≤ r i ≤ n ( 1 ≤ i ≤ m ) 1\le l_i\le r_i\le n(1\le i\le m) 1lirin(1im) 1 ≤ m ≤ 1 0 5 1\le m\le 10^5 1m105

解题分析

这道题相当于这一道题加上一个偏移量 x x x, 再按位贪心。

因为有了这个偏移量, 我们没法单纯地在 T r i e Trie Trie树上跳(因为可能存在进位的情况), 只好掏出主席树, 每次查询的时候查询对应序列区间是否有权值在 [ l b , r b ] [lb,rb] [lb,rb]之间的值, 然后再按位贪心即可。
总复杂度 O ( N l o g 2 ( N ) ) O(Nlog^2(N)) O(Nlog2(N))

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstdlib>
#define R register
#define W while
#define IN inline
#define gc getchar()
#define MX 200500
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
int n, m, cnt, root[MX];
struct Node {int son[2], sum;} tree[MX << 5];
namespace PT
{
	#define ls tree[now].son[0]
	#define rs tree[now].son[1]
	#define pls tree[pre].son[0]
	#define prs tree[pre].son[1]
	void insert(int &now, R int pre, R int lef, R int rig, R int pos)
	{
		now = ++cnt; tree[now] = tree[pre]; tree[now].sum++;
		if(lef == rig) return;
		int mid = lef + rig >> 1;
		if(pos <= mid) insert(ls, pls, lef, mid, pos);
		else insert(rs, prs, mid + 1, rig, pos);
	}
	int query (R int now, R int pre, R int lef, R int rig, R int lb, R int rb)
	{
		if(lef >= lb && rig <= rb) return tree[now].sum - tree[pre].sum;
		int mid = lef + rig >> 1, ret = 0;
		if(lb <= mid) ret += query(ls, pls, lef, mid, lb, rb);
		if(rb  > mid) ret += query(rs, prs, mid + 1, rig, lb, rb);
		return ret;
	}
	#undef ls
	#undef rs
	#undef pls
	#undef prs
}
int main(void)
{
	int b, x, l, r, ans, typ, lb, rb;
	in(n), in(m);
	for (R int i = 1; i <= n; ++i)
	in(b), PT::insert(root[i], root[i - 1], 0, 200000, b);
	for (R int i = 1; i <= m; ++i)
	{
		in(b), in(x), in(l), in(r); ans = 0;
		for (R int digit = 18; ~digit; --digit)
		{
			if(b & (1 << digit)) lb = ans, rb = ans + (1 << digit) - 1, typ = 0;
			else lb = ans + (1 << digit), rb = ans + (1 << digit + 1) - 1, typ = 1;
			if(!PT::query(root[r], root[l - 1], 0, 200000, std::max(lb - x, 0), std::min(rb - x, 200000))) typ ^= 1;
			ans += typ << digit;
		}
		printf("%d\n", ans ^ b);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值