zoukankan      html  css  js  c++  java
  • 【BZOJ4571】[SCOI2016] 美味(主席树)

    点此看题面

    大致题意: 给你一个序列(a),然后每次询问(max_{i=l}^r(a_i+x) xor b)

    大致思路

    首先,我们要知道一个简单的性质:位运算时位与位之间是互不影响的

    而且,要注意:二进制数比大小先看高位

    所以,我们可以从高位往低位枚举,每次判断当前位置是否可以选择为(1),且能选尽量选。

    那么如何判断当前位是否可以选择为(1)呢?

    判断当前位是否可以选择为(1)

    假设当前处理到第(i)位,且当前答案为(ans)

    由于我们是从高位往低位枚举的,所以第(i+1)(sim)(17)位((log_2100000≈17))实际上已经确定了。

    因为我们要尽量让当前位置为(1),所以就要让最后取值范围为([ans+2^i,ans+2^{i+1}-1]),不难发现,这段区间内的数第(i)位都是(1)

    既然我们要让((a_i+x) ext{^}bin[ans+2^i,ans+2^{i+1}-1]),由于(b)是定值,不难想到将(in)左边式子中的(b)移到右边去。

    由于( ext{^})运算的性质:(a ext{^}b=c=>a=b ext{^}c),可得(a_i+xin[(ans+2^i) ext{^}b,(ans+2^{i+1}-1) ext{^}b])

    注意,由于第(1sim i)位的数字我们是不管的,所以我们依然要将左边界第(1sim i)位全部改为(0),右边界第(1sim i)位全部改为(1)

    即左边界(L=(((ans+2^i) ext{^}b)>>i)<<i),右边界(R=((((ans+2^{i+1}-1) ext{^}b)>>i)<<i)+2^i-1)

    两边同时减去(x),得:(a_iin[L-x,R-x])

    也就是说,如果([l,r])范围内存在一个(i)满足(a_iin[L-x,R-x]),就可以将(ans)加上(2^i)了。

    而这可以用主席树来进行维护。

    于是这道题就做完了。

    代码

    #include<bits/stdc++.h>
    #define N 200000
    #define Log 17
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    #define Gmin(x,y) (x>(y)&&(x=(y)))
    using namespace std;
    int n,a[N+5];
    class Class_FIO
    {
        private:
            #define Fsize 100000
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
            #define pc(ch) (void)(FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,Fsize,stdout),Fout[(FoutSize=0)++]=ch))
            int Top,FoutSize;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize];
        public:
            Class_FIO() {A=B=Fin;}
            inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));}
            inline void writeln(int x) {if(!x) return pc('0'),pc('
    ');while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);pc('
    ');}
            inline void clear() {fwrite(Fout,1,FoutSize,stdout),FoutSize=0;}
    }F;
    class Class_ChairmanTree//主席树
    {
        private:
            #define TreeSize 100000
            #define LogN 20
            int tot,Root[N+5];
            struct Tree
            {
                int Son[2],Size;
            }node[N*LogN+5];
            inline void ins(int l,int r,int &rt,int lst,int val)
            {
                if(node[rt=++tot]=node[lst],++node[rt].Size,!(l^r)) return;
                register int mid=l+r>>1;
                val<=mid?ins(l,mid,node[rt].Son[0],node[lst].Son[0],val):ins(mid+1,r,node[rt].Son[1],node[lst].Son[1],val);
            }
            inline bool qry(int l,int r,int rt1,int rt2,int ql,int qr)
            {
                if(ql<=l&&r<=qr) return node[rt2].Size^node[rt1].Size;
                register int mid=l+r>>1;
                return (ql<=mid&&qry(l,mid,node[rt1].Son[0],node[rt2].Son[0],ql,qr))||(qr>mid&&qry(mid+1,r,node[rt1].Son[1],node[rt2].Son[1],ql,qr));
            }
        public:
            inline void Init(int len,int *data) {for(register int i=1;i<=len;++i) ins(0,TreeSize,Root[i],Root[i-1],data[i]);}//初始化
            inline bool Query(int l,int r,int ql,int qr) {return Gmax(ql,0),Gmin(qr,TreeSize),ql<=qr?qry(0,TreeSize,Root[l-1],Root[r],ql,qr):false;}//询问第l~r个元素中是否有数字在[ql,qr]范围内
    }ChairmanTree;
    int main()
    {
        register int i,query_tot,x,y,l,r,L,R,t,ans;
        for(F.read(n),F.read(query_tot),i=1;i<=n;++i) F.read(a[i]);
        for(ChairmanTree.Init(n,a);query_tot;--query_tot)
        {
            for(F.read(x),F.read(y),F.read(l),F.read(r),ans=0,i=Log;~i;--i)//从高位向低位枚举
                L=ans+(1<<i),R=L+(t=(1<<i)-1),ChairmanTree.Query(l,r,(((L^x)>>i)<<i)-y,(((R^x)>>i)<<i)+t-y)&&(ans|=1<<i);//判断能否选择为1
            F.writeln(ans);//输出答案
        }
        return F.clear(),0;
    }
    
  • 相关阅读:
    CHttpFile调试
    关于linux下网络编程socket 转换IP问题 inet_ntoa()
    vc使用SetTimer回调函数
    OpenGL+VC6.0开发环境搭建
    Java StringBuffer和StringBuilder类
    Java String类
    Java 异常处理
    hashcode()和equals()的作用、区别、联系
    抽象类可以继承实体类吗?
    Java 向上造型详解
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4571.html
Copyright © 2011-2022 走看看