【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";
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章