【BZOJ4103】【Thusc2015】异或运算 可持久Trie

现在再来切是不是有点晚QAQ

题目大意是给定两个正整数序列。规定矩阵(异或运算),每个询问求某个子矩阵内第k大的值。其中

注意到N和Q比较小,所以就是把序列B建成可持久Trie,然后同时跑A中的若干个数。。。

如果想不清楚可以先考虑当N=1,也就是A是一个数的情况,然后再考虑如何合并。

/**************************************************************
    Problem: 4103
    User: cqyzhb
    Language: C++
    Result: Accepted
    Time:5364 ms
    Memory:126804 kb
****************************************************************/
 
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define MAXN 300005
void _read(int &x)
{
    x=0; char ch=getchar(); bool flag=false;
    while(ch<'0' || ch>'9'){if(ch=='-')flag=true; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} if(flag)x=-x; return ;
}
int N,M,A[1005],B[MAXN],sum[32][1005],np;
int chi[MAXN*35][2],sz[MAXN*35],rt[MAXN];
void Insert(int anc,int &rt,int x)
{
    rt=++np; int now=np; sz[now]=sz[anc]+1;;
    for(int i=30;i>=0;i--)
    {
        if((1<<i)&x)
        {
            chi[now][0]=chi[anc][0]; chi[now][1]=++np; sz[chi[now][1]]=sz[chi[anc][1]]+1; 
            now=chi[now][1]; anc=chi[anc][1];
        }
        else
        {
            chi[now][1]=chi[anc][1]; chi[now][0]=++np; sz[chi[now][0]]=sz[chi[anc][0]]+1; 
            now=chi[now][0]; anc=chi[anc][0];
        }
    }
    return ;
}
void Init()
{
    _read(N);_read(M);
    for(int i=1;i<=N;i++)_read(A[i]); for(int i=1;i<=M;i++)_read(B[i]);
    rt[0]=0; np=0; sz[0]=0;
    for(int i=1;i<=M;i++)Insert(rt[i-1],rt[i],B[i]);
    for(int i=0;i<=30;i++)
    {
        sum[i][0]=0;
        for(int j=1;j<=N;j++)
        {
            if(A[j]&(1<<i))sum[i][j]=sum[i][j-1]+1;
            else sum[i][j]=sum[i][j-1];
        }
    }
    return ;
}
int tmp[1005][2];
void query(int anc,int now,int L,int R,int k)
{
    int ct=0,t=0,ans=0;
    for(int i=L;i<=R;i++)
    {
        tmp[i][0]=anc; tmp[i][1]=now;
    }
    for(int i=30;i>=0;i--)
    {
        t=0;
        for(int j=L;j<=R;j++)
        {
            if(A[j]&(1<<i))
            {
                t+=sz[chi[tmp[j][1]][1]]-sz[chi[tmp[j][0]][1]];
            }
            else
            {
                t+=sz[chi[tmp[j][1]][0]]-sz[chi[tmp[j][0]][0]];
            }
        }
        if(ct+t>=k) // 答案的这一位是0
        {
            for(int j=L;j<=R;j++)
            {
                if(A[j]&(1<<i)) // 向1那边走 
                {
                    tmp[j][0]=chi[tmp[j][0]][1];tmp[j][1]=chi[tmp[j][1]][1];
                }
                else
                {
                    tmp[j][0]=chi[tmp[j][0]][0];tmp[j][1]=chi[tmp[j][1]][0];
                }
            }           
        }
        else // 1
        {
            ans+=(1<<i); ct+=t;
            for(int j=L;j<=R;j++)
            {
                if(A[j]&(1<<i)) // 向0那边走 
                {
                    tmp[j][0]=chi[tmp[j][0]][0];tmp[j][1]=chi[tmp[j][1]][0];
                }
                else
                {
                    tmp[j][0]=chi[tmp[j][0]][1];tmp[j][1]=chi[tmp[j][1]][1];
                }
            }
        }
    }
    printf("%d\n",ans);
    return ;
}
void work()
{
    int u,d,l,r,k,Q;
    _read(Q);
    for(int i=1;i<=Q;i++)
    {
        _read(u); _read(d); _read(l); _read(r); _read(k); k=(d-u+1)*(r-l+1)+1-k;
        query(rt[l-1],rt[r],u,d,k);     
    }
    return ;
}
int main()
{
//  freopen("in.txt","r",stdin);
    Init();
    work();
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值