BZOJ 4103 [Thusc 2015]异或运算 (可持久化01Trie+二分)

题目大意:给你一个长方形矩阵,位置$i,j$上的数是$a_{i}\;xor\;b_{j}$,求某个子矩阵内第$K$大的值

最先想的是二分答案然后验证,然而是$O(qnlogmloga_{i})$,不出意外会被卡..看完题解才恍然大悟

$01Trie$是具有二分性质的!因为每个节点最多有2个儿子!

先对$b$序列建可持久化$01Trie$,记录一个$sum$表示当前节点的子树内有多少个数

对于每次询问,因为$n$很小,暴力枚举$a$进行统计,记录每个a当前在01Trie的位置

接下来就是在$01Trie$上二分了

按位从高到低枚举,统计一共有多少个数这一位是1,即每个a所在$01Trie$位置 和这一位异或值为1 的子树内,记为$tot$

如果$tot>k$,说明这一位不是1,每个$a$分别向异或值是0的地方走,然后$K-=tot$,去掉这一位填1的贡献

反之每个$a$往异或值为1的地方走

最后输出答案即可

#include <set>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 301000
#define N2 10201000
#define MM 100
#define ll long long
#define dd double  
#define uint unsigned int
#define mod 1000000007
#define idx(X) (X-'a')
#define it multiset<node>::iterator
using namespace std;

int gint()
{
    int ret=0,fh=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
    while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
    return ret*fh;
}

uint bin[35];
int n,m;
uint a[N1],b[N1],pa[N1];
int px[N1],py[N1];

struct Trie{
int ch[N2][2],num[N2],root[N1],tot;
int sum[N2],stk[N2],tp;
void init()
{
    root[0]=tot=1;int x=1;
    for(int i=30;i>=0;i--){
        ch[x][0]=++tot;
        x=ch[x][0],num[x]=1;
    }
}
void insert(int s,int rt1,int rt2,int w)
{
    int x,y,p;
    y=root[rt1];
    x=root[rt2]=++tot;
    for(int i=31;i>=0;i--){
        p=(s&bin[i])?1:0;
        ch[x][p]=++tot;
        ch[x][p^1]=ch[y][p^1];
        num[ch[x][p]]=num[ch[y][p]]+w;
        sum[ch[x][p]]=sum[ch[y][p]];
        x=ch[x][p],y=ch[y][p];
        stk[++tp]=x;
    }
    sum[x]++,stk[tp--]=0;
    while(tp){
        x=stk[tp--];
        sum[x]=sum[ch[x][0]]+sum[ch[x][1]];
    }
}
uint query(int L,int R,int l,int r,int K)
{
    int x,y,p;uint ans=0;
    y=l<0?0:root[l],x=root[r];
    int s[2],tot;
    for(int j=L;j<=R;j++)
        px[j]=x,py[j]=y;
    for(int i=31;i>=0;i--)
    {
        s[0]=0,s[1]=0,tot=0;
        for(int j=L;j<=R;j++){
            p=(a[j]&bin[i])?1:0,s[p]++;
            tot+=sum[ch[px[j]][p^1]]-sum[ch[py[j]][p^1]];
        }
        if(K>tot){
            K-=tot;
            for(int j=L;j<=R;j++){
                p=(a[j]&bin[i])?1:0;
                if(num[ch[px[j]][p]]-num[ch[py[j]][p]]>0)
                    px[j]=ch[px[j]][p],py[j]=ch[py[j]][p];
                else px[j]=py[j]=0;
            }
        }else{
            for(int j=L;j<=R;j++){
                p=(a[j]&bin[i])?1:0;
                if(num[ch[px[j]][p^1]]-num[ch[py[j]][p^1]]>0)
                    px[j]=ch[px[j]][p^1],py[j]=ch[py[j]][p^1];
                else px[j]=py[j]=0;
            }ans|=bin[i];
        }
    }return ans;
}
}T;

int main()
{
    //freopen("t1.in","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=31;i>=0;i--)
        bin[i]=(1<<i);
    for(int i=1;i<=n;i++)
        a[i]=gint();
    T.init();
    for(int i=1;i<=m;i++)
        b[i]=gint(),T.insert(b[i],i-1,i,1);
    int Q,u,d,l,r,K;
    scanf("%d",&Q);
    for(int q=1;q<=Q;q++)
    {
        u=gint(),d=gint(),l=gint(),r=gint(),K=gint();
        printf("%d\n",T.query(u,d,l-1,r,K));
    }
    return 0;
}

 

posted @ 2018-11-28 13:21  guapisolo  阅读(223)  评论(0编辑  收藏  举报