[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;
}

猜你喜欢

转载自www.cnblogs.com/skylee03/p/9179633.html