【SCOI2016】【主席樹】【貪心】美味

【描述】
一家餐廳有 n 道菜,編號 1…n ,大家對第 i 道菜的評價值爲 ai(1<=i<=n)a_i(1<=i<=n)。有 m 位顧客,第 i 位顧客的期望值爲 bi,而他的偏好值爲 xi 。因此,第 i 位顧客認爲第 j 道菜的美味度爲 biXOR(aj+xi)b_i XOR (a_j+x_i),XOR 表示異或運算。

第 i 位顧客希望從這些菜中挑出他認爲最美味的菜,即美味值最大的菜,但由於價格等因素,他只能從第 li 道到第 ri 道中選擇。請你幫助他們找出最美味的菜。

【輸入】
第1行,兩個整數,n,m,表示菜品數和顧客數。第2行,n個整數,a1a2...ana_1,a_2,...,a_n,表示每道菜的評價值。第3至m+2行,每行4個整數,b,x,l,r,表示該位顧客的期望值,偏好值,和可以選擇菜品區間。1<=n<=2×1050<=ai,bi,xi1051<=li<=ri<=n(1<=i<=m)1<=m<=1051<=n<=2×10^5,0<=ai,bi,xi<10^5,1<=li<=ri<=n(1<=i<=m);1<=m<=10^5

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

【思路】

顯然地,如果沒有xix_i,我們可以直接在可持久化trie上按位貪心即可。這道題似乎也可以用可持久化trie實現,不過不太方便。我們可以用主席樹代替可持久化trie。按位貪心,每次查詢使當前位爲1的對應區間是否有數存在,否則當前位只能爲0。這個主席樹上需要查詢的區間可以用當前已經確定的答案的前綴確定。而主席樹查詢時就可以很方便地考慮xix_i
代碼:

#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=2e5+5;
int n,m,ch[N*20|1][2],tot=1,rt[N]={1},siz[N*20|1],a,b,x,l,r,ans;
inline int red(){
    int data=0;int w=1; char ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return w==1?data:-data;
}
inline int lc(const int&x){return ch[x][0];}
inline int rc(const int&x){return ch[x][1];}
int change(int v,int l,int r,const int &pos){
	int u=++tot;siz[u]=siz[v]+1;if(l==r)return u;
	ch[u][0]=lc(v),ch[u][1]=rc(v);int mid=(l+r)>>1;
	if(pos<=mid)ch[u][0]=change(lc(v),l,mid,pos);
	else ch[u][1]=change(rc(v),mid+1,r,pos);
	return u;
}
bool query(int u,int v,int l,int r,const int&ql,const int &qr){
	if(ql>r||qr<l)return 0;if(ql<=l&&qr>=r)return siz[u]-siz[v]>0;int mid=l+r>>1;
	return query(lc(u),lc(v),l,mid,ql,qr)||query(rc(u),rc(v),mid+1,r,ql,qr);
}
int main(){
	n=red();m=red();
	for(int re i=1;i<=n;i++)rt[i]=change(rt[i-1],0,132000,red());
	while(m--){
		b=red();x=red();l=red();r=red();ans=0;
		for(int re j=17;~j;--j)
			if((b&(1<<j))&&!query(rt[r],rt[l-1],0,132000,max(0,ans-x),min(132000,ans+(1<<j)-1-x)))ans|=1<<j;
			else if(!(b&(1<<j))&&query(rt[r],rt[l-1],0,132000,max(0,ans+(1<<j)-x),min(132000,ans+(1<<j+1)-1-x)))ans|=1<<j;
		cout<<(ans^b)<<"\n";
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章