bzoj4103: [Thu Summer Camp 2015]异或运算【可持久化trie树】

Description

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

Input

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

第二行包含n个非负整数xi
第三行包含m个非负整数yj
第四行包含一个正整数p,表示询问次数
随后p行,每行均包含5个正整数,用来描述一次询问,每行包含五个正整数u,d,l,r,k,含义如题意所述。

Output

共p行,每行包含一个非负整数,表示此次询问的答案。

Sample Input

3 3

1 2 4

7 6 5

3

1 2 1 2 2

1 2 1 3 4

2 3 2 3 4

Sample Output

6

5

1

HINT

对于100%的数据,0<=Xi,Yj<2^31,

1<=u<=d<=n<=1000,

1<=l<=r<=m<=300000,

1<=k<=(d-u+1)*(r-l+1),

1<=p<=500

解题思路:

注意n很小,明显是来暴力的。
将y数组建出可持久化trie树,从高位开始贪心,记录a[u]~a[d]在trie树上的位置即可。
时间复杂度 O ( p n l o g m )

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
int getint()
{
    ll i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')c=getchar(),f=-1;
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}
const int N=300005;
int n,m,tot,a[1005],lpo[1005],rpo[1005],rt[N];
struct node{int son[2],cnt;}tr[N*35];
void insert(int y,int &x,int i,int v)
{
    tr[x=++tot]=tr[y];tr[x].cnt++;
    if(i==-1)return;
    int t=v>>i&1;
    insert(tr[y].son[t],tr[x].son[t],i-1,v);
}
int query(int l,int r,int x,int y,int k)
{
    for(int i=l;i<=r;i++)lpo[i]=x,rpo[i]=y;
    int res=0;
    for(int i=30;i>=0;i--)
    {
        int cnt=0;
        for(int j=l;j<=r;j++)
        {
            int t=a[j]>>i&1;
            cnt+=tr[tr[rpo[j]].son[t^1]].cnt-tr[tr[lpo[j]].son[t^1]].cnt;
        }
        if(k<=cnt)
        {
            res|=1<<i;
            for(int j=l;j<=r;j++)
            {
                int t=a[j]>>i&1;
                lpo[j]=tr[lpo[j]].son[t^1],rpo[j]=tr[rpo[j]].son[t^1];
            }
        }
        else
        {
            k-=cnt;
            for(int j=l;j<=r;j++)
            {
                int t=a[j]>>i&1;
                lpo[j]=tr[lpo[j]].son[t],rpo[j]=tr[rpo[j]].son[t];
            }
        }
    }
    return res;
}
int main()
{
    //freopen("lx.in","r",stdin);
    n=getint(),m=getint();
    for(int i=1;i<=n;i++)a[i]=getint();
    for(int i=1;i<=m;i++)insert(rt[i-1],rt[i],30,getint());
    for(int Q=getint(),u,d,l,r,k;Q;Q--)
    {
        u=getint(),d=getint(),l=getint(),r=getint(),k=getint();
        printf("%d\n",query(u,d,rt[l-1],rt[r],k));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cdsszjj/article/details/80409703