[SCOI2016]美味

[SCOI2016]美味

题目大意:

给定一个长度为\(n(n\le2\times10^5)\)的数列\(a_i(0\le a_i\le10^5)\)\(m(m\le10^5)\)次询问,每次询问给定\(b_i,x_i,l_i,r_i\),对于\(j\in[l_i,r_i]\),求\(b_i\oplus(a_j+x_i)\)的最大值。

思路:

对于单纯异或的情况,显然可以直接使用可持久化字典树。对于带加法的情况,我们同样可以按位考虑。对每次加入的权值建立主席树,保证主席树建立的区间为\([0,2^k)\)。每次区间左右子结点将这些数按最高位分开,在树上按位贪心,尽量选取与当前位不同的即可。由于含有加法,我们把主席树的区间平移\(x_i\)即可。时间复杂度\(\mathcal O(n\log^2n)\)

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
const int N=2e5+1,M=262144,logM=18;
const int SIZE=M*logM;
class FotileTree {
	private:
		struct Node {
			int val,left,right;
		};
		Node node[SIZE];
		int sz,new_node(const int &p) {
			node[++sz]=node[p];
			return sz;
		}
	public:
		int root[N];
		void insert(int &p,const int &b,const int &e,const int &x) {
			p=new_node(p);
			node[p].val++;
			if(b==e) return;
			const int mid=(b+e)>>1;
			if(x<=mid) insert(node[p].left,b,mid,x);
			if(x>mid) insert(node[p].right,mid+1,e,x);
		}
		int count(const int &p,const int &q,const int &b,const int &e,const int &l,const int &r) const {
			if(node[p].val-node[q].val==0) return 0;
			if(b==l&&e==r) return node[p].val-node[q].val;
			const int mid=(b+e)>>1;
			int ret=0;
			if(l<=mid) ret+=count(node[p].left,node[q].left,b,mid,l,std::min(mid,r));
			if(r>mid) ret+=count(node[p].right,node[q].right,mid+1,e,std::max(mid+1,l),r);
			return ret;
		}
		int query(const int &p,const int &q,const int &b,const int &e,const int &x,const int &a,const int &k) const {
			if(b==e) return b;
			const int mid=(b+e)>>1;
			if(a&(1<<k)) {
				if(mid>=x&&count(root[p],root[q],0,M-1,std::max(b-x,0),mid-x)) {
					return query(p,q,b,mid,x,a,k-1);
				} else {
					return query(p,q,mid+1,e,x,a,k-1);
				}
			} else {
				if(e>=x&&count(root[p],root[q],0,M-1,std::max(mid+1-x,0),e-x)) {
					return query(p,q,mid+1,e,x,a,k-1);
				} else {
					return query(p,q,b,mid,x,a,k-1);
				}
			}
		}
};
FotileTree t;
int main() {
	const int n=getint(),m=getint();
	for(register int i=1;i<=n;i++) {
		t.insert(t.root[i]=t.root[i-1],0,M-1,getint());
	}
	for(register int i=0;i<m;i++) {
		const int b=getint(),x=getint(),l=getint(),r=getint();
		printf("%d\n",b^t.query(r,l-1,0,M-1,x,b,17));
	}
	return 0;
}
posted @ 2018-06-13 20:16  skylee03  阅读(98)  评论(0编辑  收藏  举报