1. 程式人生 > >[Luogu P3293] [BZOJ 4571] [SCOI2016]美味

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

洛谷傳送門

題目描述

一家餐廳有 nn 道菜,編號 1...n1...n ,大家對第 ii 道菜的評價值為 ai(1in)a_i(1\le i\le n)。有 mm 位顧客,第 ii 位顧客的期望值為 bib_i,而他的偏好值為 xix_i 。因此,第 ii 位顧客認為第 jj 道菜的美味度為 biXOR(aj+xi)b_i\ XOR\ (a_j+x_i)XORXOR 表示異或運算。

ii 位顧客希望從這些菜中挑出他認為最美味的菜,即美味值最大的菜,但由於價格等因素,他只能從第 lil_i

i 道到第 rir_i 道中選擇。請你幫助他們找出最美味的菜。

輸入輸出格式

輸入格式:

11行,兩個整數,nnmm,表示菜品數和顧客數。

22行,nn個整數,a1a_1a2a_2,…,ana_n,表示每道菜的評價值。

33m+2m+2行,每行44個整數,bbxxllrr,表示該位顧客的期望值,偏好值,和可以選擇菜品區間。

輸出格式:

輸出 mm 行,每行 11 個整數,ymaxy_{max} ,表示該位顧客選擇的最美味的菜的美味值。

輸入輸出樣例

輸入樣例#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

說明

對於所有測試資料,1n21051\le n\le 2*10^50ai,bi,xi1050\le a_i,b_i,x_i<10^51lirin(1im)1\le l_i\le r_i\le n(1\le i\le m)1m1051\le m\le 10^5

解題分析

這道題相當於這一道題加上一個偏移量xx, 再按位貪心。

因為有了這個偏移量, 我們沒法單純地在TrieTrie樹上跳(因為可能存在進位的情況), 只好掏出主席樹, 每次查詢的時候查詢對應序列區間是否有權值在[

lb,rb][lb,rb]之間的值, 然後再按位貪心即可。 總複雜度O(Nlog2(N))O(Nlog^2(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);
	}
}