• [BZOJ4103][Thu Summer Camp 2015]异或运算 可持久化Trie树


    4103: [Thu Summer Camp 2015]异或运算

    Time Limit: 20 Sec  Memory Limit: 512 MB

    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.
     
    题解:
    看到“区间”“k小”几个关键词,我们自然想到了可持久化数据结构
    再加上“异或”,那么可持久化Trie没跑了。
    我们发现这个数据范围极不平衡……
    所以我们考虑对于M建立Trie树,这样for循环扫起来数据比较小,最多只需要同时扫2000棵Trie即可
    这样我们把n里面所有点,以及对应区间的Trie都存进vector或者其他容器里面,然后处理即可。和主席树非常相似。
    代码见下:
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <vector>
     4 using namespace std;
     5 typedef long long LL;
     6 const int M=300100,N=1010;
     7 int a,b,c,d,k,n,m,x[N];LL bin[40];
     8 struct Trie
     9 {
    10     int size;Trie *ch[2]; 
    11     Trie(){size=0;ch[0]=ch[1]=NULL;}
    12 }*null=new Trie(),*root[M];
    13 vector<Trie*>v[5];
    14 vector<int>vec;
    15 inline Trie* newTrie(){Trie *o=new Trie();o->ch[0]=o->ch[1]=null;return o;}
    16 void insert(Trie *&o,Trie *old,int val,int i)
    17 {
    18     if(i<0)return;
    19     int d=((val&bin[i])==bin[i]);
    20     o->ch[d]=newTrie();o->ch[d^1]=old->ch[d^1];
    21     o->ch[d]->size=old->ch[d]->size+1;
    22     insert(o->ch[d],old->ch[d],val,i-1);
    23 }
    24 inline int query()
    25 {
    26     v[1].clear(),v[2].clear();vec.clear();
    27     for(int i=a;i<=b;i++)
    28         vec.push_back(x[i]),v[1].push_back(root[c-1]),v[2].push_back(root[d]);
    29     int ret=0;
    30     for(int i=30;~i;i--)
    31     {
    32         int tmp=0;
    33         for(int j=0,len=v[1].size();j<len;j++)
    34         {
    35             int d=((vec[j]&bin[i])==bin[i]);
    36             tmp+=v[2][j]->ch[d^1]->size-v[1][j]->ch[d^1]->size;
    37         }
    38         if(tmp>=k)
    39         {
    40             ret|=bin[i];
    41             for(int j=0,len=v[1].size();j<len;j++)
    42             {
    43                 int d=((vec[j]&bin[i])==bin[i]);
    44                 v[1][j]=v[1][j]->ch[d^1],v[2][j]=v[2][j]->ch[d^1];
    45             }
    46         }
    47         else
    48         {
    49             k-=tmp;
    50             for(int j=0,len=v[1].size();j<len;j++)
    51             {
    52                 int d=((vec[j]&bin[i])==bin[i]);
    53                 v[1][j]=v[1][j]->ch[d],v[2][j]=v[2][j]->ch[d];
    54             }
    55         }
    56     }
    57     return ret;
    58 }
    59 int main()
    60 {
    61     int q;scanf("%d%d",&n,&m);
    62     bin[0]=1;for(int i=1;i<=35;i++)bin[i]=bin[i-1]<<1;
    63     root[0]=newTrie();null->ch[0]=null->ch[1]=null;
    64     for(int i=1;i<=n;i++)scanf("%d",&x[i]);
    65     for(int i=1;i<=m;i++)
    66         root[i]=newTrie(),scanf("%d",&a),insert(root[i],root[i-1],a,30);
    67     scanf("%d",&q);
    68     while(q--)
    69         scanf("%d%d%d%d%d",&a,&b,&c,&d,&k),printf("%d
    ",query());
    70 }
  • 相关阅读:
    Ubuntu升级软件和ubuntu升级系统的命令
    ASP 中如何根据数据库中取出的值来判定 checkbox或radio 的状态是否为选中
    C# 根据年、月、周、星期获得日期等
    鼠标右击事件
    【原创】VB利用堆栈实现算术表达式计算
    【算法】VB6实现哈夫曼编码生成的类
    【算法】VB 24点计算
    【算法】VB实现后缀表达式转中缀表达式
    C#操作Excel替换关键字 Johan
    C#递归遍历文件夹下的文件 Johan
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7281945.html
Copyright © 2020-2023  润新知