异或运算

1702:异或运算

时间限制: 2000 ms         内存限制: 524288 KB

【题目描述】

给定长度为n的数列X={x1,x2,...,xn}和长度为m的数列Y={y1,y2,...,ym},令矩阵A中第i行第j列的值Aij=xi^yj,每次询问给定矩形区域i∈[u,d],j∈[l,r],找出第k大的Aij。

【输入】

第一行包含两个正整数n,m,分别表示两个数列的长度;

第二行包含n个非负整数xi;

第三行包含m个非负整数yi;

第四行包含一个正整数p,表示询问次数;

随后p行,每行均包含5个正整数,用来描述一次询问,每行包含五个正整数u,d,l,r,k,含义如题意所述。

【输出】

共p行,每行包含一个非负整数,表示此次询问的答案。
【输入样例】

3 3
1 2 4
7 6 5
3
1 2 1 2 2
1 2 1 3 4
2 3 2 3 4

【输出样例】

6
5
1

【提示】

【数据规模】

对于100%的数据:

0≤Xi,Yj<pow(2,31),1≤u≤d≤n≤1000,1≤l≤r≤m≤300000,1≤k≤(d-u+1)×(r-l+1),1≤p≤500。

【题解】

首先考虑到枚举数的每一位,如果可以填1就这一位填1否则填0。

可以构造可持久化trie树,按位拆分加入每一个Y数组中元素。

查询:

因为p和n均很小,可以考虑枚举每一位A中元素。

查询时算出这一位取1时可以构造出好多数,如果>k则取1,否则取0,k-=个数。再将A每一位所对应的trie节点更新为其左或右儿子,即可 查出答案。

复杂度O(31*(n*p+m)).

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int M=3e5+5;
int n,m,root[M],a[1005],cnt,p,pr[1005],no[1005],ans;
struct trie
{
    int er[2],siz;
}sh[M*33];
inline int read()
{
    char c=getchar();
    int x=0,f=1;
    while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
    while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return x*f;
}
inline void pushup(int now)
{
    sh[now].siz=sh[sh[now].er[0]].siz+sh[sh[now].er[1]].siz;
}
inline int insert(int now,int pre,int x,int ge)
{
    now=++cnt;sh[now]=sh[pre];
    if(ge==-1)
    {
        sh[now].siz++;
        return now;
    }
    
    int hu=(x>>ge)&1;
    sh[now].er[hu]=insert(sh[now].er[hu],sh[pre].er[hu],x,ge-1);
    pushup(now);
    return now;
}
inline void query(int ge,int l,int r,int k)
{
    int gu=0,pan=(1<<ge);
    if(ge==-1) return;
    for(int i=l;i<=r;i++)
    {
        if(a[i]&pan) gu+=sh[sh[no[i]].er[0]].siz-sh[sh[pr[i]].er[0]].siz;
        else gu+=sh[sh[no[i]].er[1]].siz-sh[sh[pr[i]].er[1]].siz;
    }
    if(gu>=k)
    {
        for(int i=l;i<=r;i++)
        {
            if(a[i]&pan) no[i]=sh[no[i]].er[0],pr[i]=sh[pr[i]].er[0];
            else no[i]=sh[no[i]].er[1],pr[i]=sh[pr[i]].er[1];
        }
        ans|=pan;
        query(ge-1,l,r,k);
    }
    else
    {
        for(int i=l;i<=r;i++)
        {
            if(a[i]&pan) no[i]=sh[no[i]].er[1],pr[i]=sh[pr[i]].er[1];
            else no[i]=sh[no[i]].er[0],pr[i]=sh[pr[i]].er[0];
        }
        query(ge-1,l,r,k-gu);
    }
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int i=1,x;i<=m;i++)
    {
        x=read();
        root[i]=insert(root[i],root[i-1],x,30);
    }
    p=read();
    for(int i=1,x,y,z,w,u;i<=p;i++)
    {
        x=read();y=read();z=read();w=read();u=read();
        for(int j=x;j<=y;j++) pr[j]=root[z-1],no[j]=root[w];//极角米巴游
        ans=0;
        query(30,x,y,u); 
        cout<<ans<<"
";
    }
    return 0;
}
原文地址:https://www.cnblogs.com/betablewaloot/p/12146931.html