洛谷传送门
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(1≤i≤n)。有 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 1≤n≤2∗105, 0 ≤ a i , b i , x i < 1 0 5 0\le a_i,b_i,x_i<10^5 0≤ai,bi,xi<105, 1 ≤ l i ≤ r i ≤ n ( 1 ≤ i ≤ m ) 1\le l_i\le r_i\le n(1\le i\le m) 1≤li≤ri≤n(1≤i≤m); 1 ≤ m ≤ 1 0 5 1\le m\le 10^5 1≤m≤105
解题分析
这道题相当于这一道题加上一个偏移量 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);
}
}