1. 程式人生 > >【bzoj4571&&SCOI2016美味】

【bzoj4571&&SCOI2016美味】

clas xor src 為什麽 無標題 round stat trie one

4571: [Scoi2016]美味

Time Limit: 30 Sec Memory Limit: 256 MB
Submit: 656 Solved: 350
[Submit][Status][Discuss]

Description

一家餐廳有 n 道菜,編號 1...n ,大家對第 i 道菜的評價值為 ai(1≤i≤n)。有 m 位顧客,第 i 位顧客的期

望值為 bi,而他的偏好值為 xi 。因此,第 i 位顧客認為第 j 道菜的美味度為 bi XOR (aj+xi),XOR 表示異或

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

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

Input

第1行,兩個整數,n,m,表示菜品數和顧客數。

第2行,n個整數,a1,a2,...,an,表示每道菜的評價值。

第3至m+2行,每行4個整數,b,x,l,r,表示該位顧客的期望值,偏好值,和可以選擇菜品區間。

1≤n≤2×10^5,0≤ai,bi,xi<10^5,1≤li≤ri≤n(1≤i≤m);1≤m≤10^5

Output

輸出 m 行,每行 1 個整數,ymax ,表示該位顧客選擇的最美味的菜的美味值。

Sample Input

4 4

1 2 3 4
1 4 1 4
2 3 2 3
3 2 3 3
4 1 2 4

Sample Output

9
7
6
7

三步走

●維護xor最大值的話用trie樹可以搞一搞

●維護區間xor最大值可以用可持久化trie樹

●維護區間xor並支持加減的就是可持久化權值線段樹了,這就是本題的算法,用貪心+主席樹實現

貪心?肯定先確定最高位使得xor後此位為1,由此得到

策略1:從二進制高位向低位貪心,盡量滿足 b的i位與(a[j]+x)的i位不同

怎麽判斷第i位是否可以不同?可以假設(a[j]+x)的i位與b的i位不同,來確定所選的數的第i位,再判定假設是否合法。

合法的條件是什麽?記已確定的數為ans,只用查找區間內是否存在數這樣的滿足條件

1.前面位和ans相同

2.此位滿足已確定的數

不太容易懂,舉一個例子:

假設b的當前位為1,我們應盡量使a[j]+x當前位為0,前面位確定為ans,ans第i位設定為0,查找區間內是否存在 在[ans,ans+(1<<i)-1]之內的數,如果有,則此位可以為0

技術分享

判斷區間的數的個數,權值線段樹

但此時我們註意到查找是雙關鍵字的,一個是區間一個是權值,所以用主席樹來完成操作

總結得出

策略2:用主席樹判斷區間數的存在性問題來確定當前位究竟是什麽

到了這裏,此題也就差不多了,但有幾個細節需要註意

●主席樹空間開夠(我就是這裏錯了好久--為什麽dev不報RE而是亂搞數組啊!!)

●由於我們查詢的數是a[j]+x,而樹中插入的是a[],所以查詢區間統一減去x並考慮區間是否超界

●最後註意,我們的到的ans是選出來的數,所以輸出時要xor b

沒有了-------------------------------------------------------------------

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#define ll long long
#define N 200005
#define mx (1<<18)-1
using namespace std;
int n,m,a[N],rt[N],ls[N<<5],rs[N<<5],sum[N<<5],sz;
void insert(int pre,int &u,int l,int r,int pos){
	u=++sz;ls[u]=ls[pre];rs[u]=rs[pre];sum[u]=sum[pre]+1;
	if(l==r)return;int mid=(l+r)>>1;
	if(pos<=mid)insert(ls[pre],ls[u],l,mid,pos);
	else insert(rs[pre],rs[u],mid+1,r,pos);
}

int query(int pre,int u,int l,int r,int L,int R){
	if(L<=l&&r<=R)return sum[u]-sum[pre];
	int mid=(l+r)>>1;int t=0;
	if(L<=mid)t+=query(ls[pre],ls[u],l,mid,L,R);
	if(R>mid)t+=query(rs[pre],rs[u],mid+1,r,L,R);
	return t;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	insert(rt[i-1],rt[i],0,mx,a[i]);
	for(int i=1;i<=m;i++){
		int b,x,l,r;
		scanf("%d%d%d%d",&b,&x,&l,&r);
		int ans=0;
		for(int j=17;j>=0;j--){
			if(b&(1<<j)){
				int L=max(ans-x,0),R=ans+(1<<j)-x-1;
				if(R<0||!query(rt[l-1],rt[r],0,mx,L,R))ans^=(1<<j);
			}
			else{
				ans^=(1<<j);
				int L=max(ans-x,0),R=ans+(1<<j)-x-1;
				if(R<0||!query(rt[l-1],rt[r],0,mx,L,R))ans^=(1<<j);
			}
		}
		printf("%d\n",ans^b);
	}
	return 0;
}

  

【bzoj4571&&SCOI2016美味】