zoukankan      html  css  js  c++  java
  • BZOJ2741 FOTILE模拟赛L(分块+可持久化trie)

      显然做个前缀和之后变成询问区间内两个数异或最大值。

      一种暴力做法是建好可持久化trie后直接枚举其中一个数查询,复杂度O(nmlogv)。

      观察到数据范围很微妙。考虑瞎分块。

      设f[i][j]为第i个块中的数和第j个数的异或最大值。显然建一棵可持久化trie就可以以O(n√nlogv)的复杂度搞出来。

      有了这个后考虑怎么查询。对于完整的块内的数,给f再搞一个st表就可以了。而其他部分暴力枚举每个数,在可持久化trie上查询即可。

      常数巨大。块大小改成√nlogn后在darkbzoj上差10ms就T了,bzoj上自然过不了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 12010
    #define BLOCK 120
    #define u(x,p) x>>p&1^1
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,a[N],f[BLOCK][N][14],root[N],L[BLOCK],R[BLOCK],pos[N],lg2[N],cnt=0,lastans,block;
    struct data{int ch[2],s;
    }tree[N<<5];
    void ins(int &k,int x,int p)
    {
        tree[++cnt]=tree[k];k=cnt;tree[k].s++;
        if (p<0) return;
        ins(tree[k].ch[x>>p&1],x,p-1);
    }
    int query(int l,int r,int x,int p)
    {
        if (p<0) return 0;
        if (tree[tree[r].ch[u(x,p)]].s>tree[tree[l].ch[u(x,p)]].s)
        return query(tree[l].ch[u(x,p)],tree[r].ch[u(x,p)],x,p-1)+(1<<p);
        else query(tree[l].ch[x>>p&1],tree[r].ch[x>>p&1],x,p-1);
    }
    void build()
    {
        for (int i=1;i<=n;i++)
        {
            root[i]=root[i-1];
            ins(root[i],a[i],30);
        }
    }
    int query(int i,int x,int y)
    {
        return max(f[i][x][lg2[y-x+1]],f[i][y-(1<<lg2[y-x+1])+1][lg2[y-x+1]]);
    }
    void divide()
    {
        lg2[1]=0;
        for (int i=2;i<=n;i++)
        {
            lg2[i]=lg2[i-1];
            if ((2<<lg2[i])<=i) lg2[i]++;
        }
        block=sqrt(n*lg2[n]);block=min(max(block,1),n);
        for (int i=1;i<=n/block;i++) L[i]=(i-1)*block+1,R[i]=i*block;
        if (n%block) L[n/block+1]=(n/block)*block+1,R[n/block+1]=n,block=n/block+1;
        else block=n/block;
        for (int i=1;i<=block;i++)
            for (int j=L[i];j<=R[i];j++)
            pos[j]=i;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=block;j++)
            f[j][i][0]=query(root[L[j]-1],root[R[j]],a[i],30);
        for (int i=1;i<=block;i++)
            for (int j=1;j<14;j++)
                for (int k=1;k<=n;k++)
                f[i][k][j]=max(f[i][k][j-1],f[i][min(n,k+(1<<j-1))][j-1]);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj2741.in","r",stdin);
        freopen("bzoj2741.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read()+1,m=read();
        for (int i=2;i<=n;i++) a[i]=a[i-1]^read();
        build();
        divide();
        for (int i=1;i<=m;i++)
        {
            int x=((unsigned int)read()+lastans)%(n-1)+1,y=((unsigned int)read()+lastans)%(n-1)+1;
            if (x>y) swap(x,y);y++;
            lastans=0;
            for (int j=pos[x]+1;j<pos[y];j++)
            lastans=max(lastans,query(j,x,y));
            if (pos[x]==pos[y])
            {
                for (int j=x;j<=y;j++)
                lastans=max(lastans,query(root[x-1],root[y],a[j],30));
            }
            else
            {
                for (int j=x;j<L[pos[x]+1];j++)
                lastans=max(lastans,query(root[x-1],root[y],a[j],30));
                for (int j=y;j>R[pos[y]-1];j--)
                lastans=max(lastans,query(root[x-1],root[y],a[j],30));
            }
            printf("%d
    ",lastans);
        }
        return 0;
    }
  • 相关阅读:
    c#反射动态创建窗体
    ImageSwitcher 图片切换器
    viewSwitcher 切换视图
    ratingBar 星级评分条
    seekBar拖动滑块
    pythonUDP发送结构体,对齐到C++结构体
    pyqt5界面
    progressbar
    SVN服务器搭建和使用(一)
    关于MBR、GPT以及BIOS引导模式区分
  • 原文地址:https://www.cnblogs.com/Gloid/p/9607135.html
Copyright © 2011-2022 走看看