zoukankan      html  css  js  c++  java
  • bzoj 2741 可持久化trie

      首先我们设si为前i个数的xor和,那么对于询问区间[i,j]的xor和,就相当于si-1^sj,那么对于这道题的询问我们可以处理处si,然后对于询问[l,r],可以表示为在区间[l-1,r]里找两个数使得这两个数的xor值最大,对于区间中找一个数使得xor一个已知数的值最大我们可以用可持久化trie来完成(有疑问请移步http://www.cnblogs.com/BLADEVIL/p/3669219.html),设询问query(l,r,x)表示x与区间[l,r]的数的xor值最大值。那么我们可以将这n个数分为sqrt(n)个块,我们设head[i]为第i个块的最开始元素,w[i][j]为从第i个块的第一个元素开始,到第j个数的区间中,任意找两个数的xor值最大,那么易得到转移方程w[i][j]=max(w[i][j],w[i][j-1]+query(head[i],j-1,a[j]))。这个的时间复杂度是o(sqrt(n)*n*logn)的,然后对于询问[l,r],我们设l后面第一个块为x块,那么ans=max(w[x][r],max(l,r,a[j])),j∈[l,head[x]-1]。

      备注:开始的时候以为题目说a[i]不会超过32767,后来发现好像是2147483647,然后改了trie的深度之后发现总是RE,因为我写的trie是先建一个空树,然后再插入节点的,31层的满二叉树当然没有办法建出来,那么改成了直接插入,发现还是WA,因为上一次的答案可能只比2147483647小一点,那么加上这次询问的值就会超过int,所以先强制转成long long然后%n就好了。

        开始以为RE是内存的问题,所以开大了好多,懒得改了就这样吧。

    /**************************************************************
        Problem: 2741
        User: BLADEVIL
        Language: C++
        Result: Accepted
        Time:8148 ms
        Memory:41680 kb
    ****************************************************************/
     
    //By BLADEVIL
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 20000
    #define maxm 400
     
    using namespace std;
     
    struct tree {
        int son[2];
        int cnt;
        tree() {
            memset(son,0,sizeof son);
            cnt=0;
        }
    }t[40*maxn];
     
    struct rec {
        int key,num,rot;
        rec() {
            key=num=rot=0;
        }
    }a[maxn];
     
    int n,m,len,sum,tot;
    int w[maxm][maxn],head[maxm];
     
    void insert(int &x,int rot,int y,int dep) {
        if (!x) x=++tot;
        if (dep==-1) {
            t[x].cnt=t[rot].cnt+1;
            return ;
        }
        if (y&(1<<dep)) {
            insert(t[x].son[1],t[rot].son[1],y,dep-1); 
            t[x].son[0]=t[rot].son[0];
        } else {
            insert(t[x].son[0],t[rot].son[0],y,dep-1);
            t[x].son[1]=t[rot].son[1];
        }
        t[x].cnt=t[rot].cnt+1;
    }
     
    int query(int lx,int rx,int y,int dep) {
        if (dep==-1) return 0;
        if (y&(1<<dep)) {
            if (t[t[rx].son[0]].cnt-t[t[lx].son[0]].cnt) 
                return (1<<dep)+query(t[lx].son[0],t[rx].son[0],y,dep-1); else
                return query(t[lx].son[1],t[rx].son[1],y,dep-1);
        } else {
            if (t[t[rx].son[1]].cnt-t[t[lx].son[1]].cnt)
                return (1<<dep)+query(t[lx].son[1],t[rx].son[1],y,dep-1); else
                return query(t[lx].son[0],t[rx].son[0],y,dep-1);
        }
    }
     
    int main() {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%d",&a[i].key);
        for (int i=1;i<=n;i++) a[i].key^=a[i-1].key;
        sum=len=sqrt(n); if (len*len<n) len++,sum=(n+len-1)/len;
        //printf("%d %d
    ",len,sum);
        for (int i=1;i<=n;i++) if (!head[a[i].num=(i+len-1)/len]) head[a[i].num]=i; head[sum+1]=n+1;
        //for (int i=1;i<=n;i++) printf("%d ",a[i].key); printf("
    ");
        //for (int i=1;i<=sum;i++) printf("%d ",head[i]);
        for (int i=1;i<=n;i++) insert(a[i].rot,a[i-1].rot,a[i].key,30);
        for (int i=1;i<=sum;i++)
            for (int j=head[i];j<=n;j++) 
                w[i][j]=max(w[i][j-1],query(a[head[i]-1].rot,a[j].rot,a[j].key,30));
        /*
        for (int i=1;i<=sum;i++) {
            for (int j=1;j<=n;j++) printf("%d ",w[i][j]);
            printf("
    ");
        }
        */
        int ans=0;
        while (m--) {
            int l,r; scanf("%d%d",&l,&r); int x,y;
            x=((long long)l+ans)%n+1; y=((long long)r+ans)%n+1;
            l=min(x,y); r=max(x,y); ans=0; l--;
            if (a[l].num==a[r].num) {
                for (int i=l;i<=r;i++) ans=max(ans,query(a[l-1].rot,a[r].rot,a[i].key,30));
            } else {
                ans=w[a[l].num+1][r]; //printf("%d %d %d
    ",ans,a[l].num+1,r); 
                for (int i=l;i<=head[a[l].num+1]-1;i++) ans=max(ans,query(a[l-1].rot,a[r].rot,a[i].key,30));
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    2020年“安洵杯”四川省大学生信息安全技术大赛 Misc WP
    整数划分问题
    二叉树根节点到叶子节点的所有路径和
    java正则表达式
    搜狗笔试
    跟谁学0923笔试
    360 笔试0926
    度小满0920
    TreeMap 常用函数
    达达0920
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3679653.html
Copyright © 2011-2022 走看看