[Luogu P3293] [BZOJ 4571] [SCOI2016]美味
阿新 • • 發佈:2018-12-13
洛谷傳送門
題目描述
一家餐廳有 道菜,編號 ,大家對第 道菜的評價值為 。有 位顧客,第 位顧客的期望值為 ,而他的偏好值為 。因此,第 位顧客認為第 道菜的美味度為 , 表示異或運算。
第 位顧客希望從這些菜中挑出他認為最美味的菜,即美味值最大的菜,但由於價格等因素,他只能從第 道到第 道中選擇。請你幫助他們找出最美味的菜。
輸入輸出格式
輸入格式:
第行,兩個整數,,,表示菜品數和顧客數。
第行,個整數,,,…,,表示每道菜的評價值。
第至行,每行個整數,,,,,表示該位顧客的期望值,偏好值,和可以選擇菜品區間。
輸出格式:
輸出 行,每行 個整數, ,表示該位顧客選擇的最美味的菜的美味值。
輸入輸出樣例
輸入樣例#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);
}
}