[SCOI2016]美味
题目大意:
给定一个长度为(n(nle2 imes10^5))的数列(a_i(0le a_ile10^5))。(m(mle10^5))次询问,每次询问给定(b_i,x_i,l_i,r_i),对于(jin[l_i,r_i]),求(b_ioplus(a_j+x_i))的最大值。
思路:
对于单纯异或的情况,显然可以直接使用可持久化字典树。对于带加法的情况,我们同样可以按位考虑。对每次加入的权值建立主席树,保证主席树建立的区间为([0,2^k))。每次区间左右子结点将这些数按最高位分开,在树上按位贪心,尽量选取与当前位不同的即可。由于含有加法,我们把主席树的区间平移(x_i)即可。时间复杂度(mathcal O(nlog^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
",b^t.query(r,l-1,0,M-1,x,b,17));
}
return 0;
}