版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/82936240
洛谷传送门
BZOJ传送门
题目描述
一家餐厅有 道菜,编号 ,大家对第 道菜的评价值为 。有 位顾客,第 位顾客的期望值为 ,而他的偏好值为 。因此,第 位顾客认为第 道菜的美味度为 , 表示异或运算。
第 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 道到第 道中选择。请你帮助他们找出最美味的菜。
输入输出格式
输入格式:
第 行,两个整数, , ,表示菜品数和顾客数。
第 行, 个整数, , ,…, ,表示每道菜的评价值。
第 至 行,每行 个整数, , , , ,表示该位顾客的期望值,偏好值,和可以选择菜品区间。
输出格式:
输出 行,每行 个整数, ,表示该位顾客选择的最美味的菜的美味值。
输入输出样例
输入样例#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
说明
对于所有测试数据, , , ;
解题分析
这道题相当于这一道题加上一个偏移量 , 再按位贪心。
因为有了这个偏移量, 我们没法单纯地在
树上跳(因为可能存在进位的情况), 只好掏出主席树, 每次查询的时候查询对应序列区间是否有权值在
之间的值, 然后再按位贪心即可。
总复杂度
代码如下:
#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);
}
}