zoukankan      html  css  js  c++  java
  • 区间异或和=贪心+可持久化字典树?

      先不管那个+d,我们来考虑正常的可持久化字典树.总的思想就是贪心:用一个主席树模仿字典树,我发现当线段树总区间是2^n-1时每个小区间内部的01分布就与深度有关.比如左半边这一位都是0右边都是1这个样子.这样就可以O(1)地判断某个区间内有没有数,因为是一整个的区间,又因为向下到达根节点需要logn,总的复杂度为m*logn.

      

    int i,k,tx,ty;
    int n,m,a[10000],o[10000],c[1000],sum;
    int tot,rt[1000],lc[1000],rc[1000];
    void build(int &now,int l,int r){
        tot++;
        now=tot;
        if(l==r)
            return;
        int mid=(l+r)>>1;
        build(lc[now],l,mid);
        build(rc[now],mid+1,r);
        return ;
    }
    int built(int now,int l,int r){
        tot++;
        int t=tot;
        lc[t]=lc[now];rc[t]=rc[now];c[t]=c[now]+1;
        if(l==r)
            return t;
        int mid=(l+r)>>1;
        if(k<=mid)lc[t]=built(lc[t],l,mid);
        else      rc[t]=built(rc[t],mid+1,r);
        return t;
    }    
    int ask(int x,int y,int l,int r){
        if(l==r)
            return l;
        int mid=(l+r)>>1;
        if((l^k)>(r^k))
            if(c[lc[y]]-c[lc[x]])
                return ask(lc[x],lc[y],l,mid);
            else 
                return ask(rc[x],rc[y],mid+1,r);
        else
            if((c[rc[y]]-c[rc[x]]))
                return ask(rc[x],rc[y],mid+1,r);
            else
                return ask(lc[x],lc[y],l,mid);
    }
    int main(){
        n=read();m=read();
        for(i=1;i<=n;i++)
            a[i]=o[i]=read(),sum=max(sum,a[i]);
        sum=1<<int(log2(sum*1.0)+1);
        sum--;
        build(rt[0],0,sum); 
        for(i=1;i<=n;i++){
            k=o[i];
            rt[i]=built(rt[i-1],0,sum);
        }
        for(i=1;i<=m;i++){
            tx=read();ty=read();k=read();
            cout<<(k^ask(rt[tx-1],rt[ty],0,sum))<<endl;
        }
        return 0;
    }
    不偏移

       然后考虑偏移.这个复杂度要变成m*log2n了.这主要是由于偏移后由判断一整个区间[x,y]变成了判断区间[x-d,y-d]内是否有数,这个过程需要我们向下寻找了,每次最坏要向下查logn次,总的复杂度就要再乘上logn.

      代码还是不难写的,只需要把上面的if内的判断改成一个函数就行.

    using namespace std;
    int i,k,tx,ty,d;
    int n,m,a[10000],o[10000],c[1000],sum;
    int tot,rt[1000],lc[1000],rc[1000];
    void build(int &now,int l,int r){
        tot++;
        now=tot;
        if(l==r)
            return;
        int mid=(l+r)>>1;
        build(lc[now],l,mid);
        build(rc[now],mid+1,r);
        return ;
    }
    int built(int now,int l,int r){
        tot++;
        int t=tot;
        lc[t]=lc[now];rc[t]=rc[now];c[t]=c[now]+1;
        if(l==r)
            return t;
        int mid=(l+r)>>1;
        if(k<=mid)lc[t]=built(lc[t],l,mid);
        else      rc[t]=built(rc[t],mid+1,r);
        return t;
    }
    bool check(int x,int y,int tl,int tr,int l,int r)
    {
        if(l==r||(tl<=l&&r<=tr))
            return c[y]-c[x];
        int mid=(l+r)>>1;
        return (tl<=mid&&check(lc[x],lc[y],tl,tr,l,mid)||(tr>mid&&check(rc[x],rc[y],tl,tr,mid+1,r)));//运用短路的性质减少代码与时间
    }
    int ask(int x,int y,int l,int r){
        if(l==r)
            return l;
        int mid=(l+r)>>1;
        if((l^k)>(r^k))
            //if(c[lc[y]]-c[lc[x]])
            if(check(rt[tx-1],rt[ty],max(l-d,0),max(mid-d,0),0,sum) )
                return ask(lc[x],lc[y],l,mid);
            else 
                return ask(rc[x],rc[y],mid+1,r);
        else
            //if((c[rc[y]]-c[rc[x]]))
            if(check(rt[tx-1],rt[ty],max(mid+1-d,0),max(r-d,0),0,sum))
                return ask(rc[x],rc[y],mid+1,r);
            else
                return ask(lc[x],lc[y],l,mid);
    }
    int main(){
        n=read();m=read();
        for(i=1;i<=n;i++)
            a[i]=o[i]=read(),sum=max(sum,a[i]);
        sum=1<<int(log2(sum*1.0)+1);
        sum=sum<<1;
        sum--;
        //cout<<sum<<endl;
        build(rt[0],0,sum); 
        for(i=1;i<=n;i++){
            k=o[i];
            rt[i]=built(rt[i-1],0,sum);
        }
        for(i=1;i<=m;i++){
            tx=read();ty=read();k=read();d=read();
            cout<<(k^(ask(rt[tx-1],rt[ty],0,sum)))<<endl;
        }
        return 0;
    }
    带偏移
  • 相关阅读:
    文学、哲学段子
    文学、哲学段子
    js技术要点---JS 获取网页源代码
    泛型类,泛型方法,泛型委托的定义方法
    数组元素的逆序数
    stm32 ARM中的RO、RW和ZI DATA
    poj 3040 Allowance 贪心
    schedule()函数的调用时机(周期性调度)
    以JTextPanel为例Swing的鼠标事件详解
    实习生面试总结
  • 原文地址:https://www.cnblogs.com/qywyt/p/10211215.html
Copyright © 2011-2022 走看看