BZOJ 4103 [Thu Summer Camp 2015]异或运算 可持久化Trie

对矩阵求第k大xor值。

注意到数据范围长宽严重失调(误

所以对于每列维护可持久化Trie。

然后查询就由BZOJ 3261推广一下就好啦。

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 1001, M = 300001;
using namespace std;
struct Trie {
    Trie* c[2]; int size;
    Trie() { c[0] = c[1] = NULL; size = 0; }
    Trie(Trie *l, Trie *r, int sz) { c[0] = l, c[1] = r, size = sz; }
    void* operator new(size_t) {
        static Trie pool[M * 60], *pointer = pool;
        return pointer++;
    }
    static Trie* put(Trie *p, int x, int digit) {
        if (!digit)
            return new Trie(p->c[0], p->c[1], p->size + 1);
        if (x & digit)
            return new Trie(p->c[0], put(p->c[1], x, digit >> 1), p->size + 1);
        else
            return new Trie(put(p->c[0], x, digit >> 1), p->c[1], p->size + 1);
    }
    static int get(Trie *p1[], Trie *p2[], int *x, int len, int digit, int k) {
        int i, sz = 0;
        if (!digit)
            return 0;
        #define rson (bool(~x[i] & digit))
        #define  son (bool( x[i] & digit))
        for (i = 1; i <= len; i++)
            sz += p1[i]->c[rson]->size,
            sz -= p2[i]->c[rson]->size;
        if (k <= sz) {
            for (i = 1; i <= len; i++)
                p1[i] = p1[i]->c[rson],
                p2[i] = p2[i]->c[rson];
            return digit | get(p1, p2, x, len, digit >> 1, k);
        } else {
            for (i = 1; i <= len; i++)
                p1[i] = p1[i]->c[ son],
                p2[i] = p2[i]->c[ son];
            return         get(p1, p2, x, len, digit >> 1, k - sz);
        }
    }
};
int main() {
    static int x[N], y[M], a[N];
    static Trie *p1[N], *p2[N], *trie[M];
    int i, dep = 1 << 30, n, m, q, l1, l2, r1, r2, k;
    scanf("%d%d", &n, &m);
    for (i = 1; i <= n; i++) scanf("%d", &x[i]);
    for (i = 1; i <= m; i++) scanf("%d", &y[i]);
    trie[0] = new Trie();
    trie[0]->c[0] = trie[0]->c[1] = trie[0];
    for (i = 1; i <= m; i++)
        trie[i] = Trie::put(trie[i - 1], y[i], dep);
    scanf("%d", &q);
    while (q--) {
        scanf("%d%d%d%d%d", &l1, &r1, &l2, &r2, &k);
        int len = r1 - l1 + 1;
        fill(p1 + 1, p1 + len + 1, trie[r2]);
        fill(p2 + 1, p2 + len + 1, trie[l2 - 1]);
        memcpy(a + 1, x + l1, sizeof(int) * len);
        printf("%d\n", Trie::get(p1, p2, a, len, dep, k));
    }
    return 0;
}


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

Time Limit: 20 Sec   Memory Limit: 512 MB
Submit: 171   Solved: 96
[ Submit][ Status][ Discuss]

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值