51Nod——1295 XOR key(贪心+可持久化字典树)

题目来源: HackerRank
基准时间限制:1.5 秒 空间限制:262144 KB

给出一个长度为N的正整数数组A,再给出Q个查询,每个查询包括3个数,L, R, X (L <= R)。求A[L] 至 A[R] 这R - L + 1个数中,与X 进行异或运算(Xor),得到的最大值是多少?

Input

第1行:2个数N, Q中间用空格分隔,分别表示数组的长度及查询的数量(1 <= N <= 50000, 1 <= Q <= 50000)。
第2 - N+1行:每行1个数,对应数组A的元素(0 <= A[i] <= 10^9)。
第N+2 - N+Q+1行:每行3个数X, L, R,中间用空格分隔。(0 <= X <= 10^9,0 <= L <= R < N)

Output

输出共Q行,对应数组A的区间[L,R]中的数与X进行异或运算,所能得到的最大值。

Input示例

15 8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
10 5 9
1023 6 6
33 4 7
182 4 9
181 0 12
5 9 14
99 7 8
33 9 13

Output示例

13
1016
41
191
191
15
107
47

考虑查询的数,我们可以从高位到低位进行贪心。由于只有查询,我们可以建立一个可持久化字典树。然后进行区间的从高位到地位进行贪心

#include <bits/stdc++.h>
#define rr(x) freopen(x,"r",stdin)
#define ww(x) freopen(x,"w",stdout)
using namespace std;
const int Max = 55000;
const int Maxn = 1555000;
const int Log = 30;
int tr[Maxn][2],num[Maxn],root[Max];
bool bt[Log];
int n,m,top,da;
void Insert(int v,int &x,int y) {
    x = ++top;
    for(int i = 0;i<2;i++) tr[x][i] = tr[y][i];
    num[x] = num[y]+1;
    if(!v) return ;
    Insert(v-1,tr[x][bt[v-1]],tr[y][bt[v-1]]);
}
int qu(int v,int x,int y) {
    if(!v) return 0;
    if(num[tr[x][bt[v-1]]] > num[tr[y][bt[v-1]]]) return qu(v-1,tr[x][bt[v-1]],tr[y][bt[v-1]])+(1<<(v-1));
    else return  qu(v-1,tr[x][1-bt[v-1]],tr[y][1-bt[v-1]]);
    return 0;
}
int main() {
    top = 0;
    scanf("%d %d",&n,&m);
    for(int i = 1;i<=n;i++) {
        scanf("%d",&da);
        for(int j = 0;j<Log;j++,da/=2) bt[j] = da % 2;
        Insert(Log,root[i],root[i-1]);
    }
    int l,r;
    for(int i = 1;i<=m;i++) {
        scanf("%d %d %d",&da,&l,&r);
        for(int j = 0;j<Log;j++,da/=2) bt[j] = (1-(da % 2));
        printf("%d\n",qu(Log,root[r+1],root[l]));
    }
    return 0;
}

你可能感兴趣的:(51Nod——1295 XOR key(贪心+可持久化字典树))