51nod 1295 XOR key 01trie(可持久化字典树坑已填)
来源:互联网 发布:suse 11 yum 编辑:程序博客网 时间:2024/05/17 00:51
题目:
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1295
题意:
给出一个长度为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进行异或运算,所能得到的最大值。
思路:
查找跟x异或的最大值显然是用字典树,然而这个题每个询问都有一个区间,是查询这个区间内的数和x的异或的最大值,这就比较忧伤了,刚开始套了个莫队,TLE了,然后直接在插入的时候记录trie里面的边属于哪个位置的数字,查询的时候看这条边是不是在查询区间内。。。
#include <bits/stdc++.h>using namespace std;const int N = 50000 + 10, M = 2, INF = 0x3f3f3f3f;int tot;int len = 31, block_sz;int a[N], ans[N];struct node{ node *next[M]; vector<int>vec; void init() { memset(next, 0, sizeof next); vec.clear(); }}trie[N*31], *root;node * new_node(){ trie[tot].init(); return trie + tot++;}void trie_init(){ tot = 0; root = new_node();}void trie_insert(int val, int id){ node *p = root; for(int i = len-1; i >= 0; i--) { int j = 1 & (val >> i); if(p->next[j] == NULL) p->next[j] = new_node(); p->next[j]->vec.push_back(id); p = p->next[j]; }}bool check(node* &p, int l, int r){ return upper_bound(p->vec.begin(), p->vec.end(), r) - lower_bound(p->vec.begin(), p->vec.end(), l);}int trie_query(int val, int l, int r){ node *p = root; int ans = 0; for(int i = len-1; i >= 0; i--) { int j = ! (1 & (val >> i)); if(p->next[j] && check(p->next[j], l, r)) { ans = ans * 2 + 1; p = p->next[j]; } else { ans = ans * 2 + 0; p = p->next[!j]; } } return ans;}int main(){ int n, m; trie_init(); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); trie_insert(a[i], i); } int x, l, r; for(int i = 1; i <= m; i++) { scanf("%d%d%d", &x, &l, &r); l++, r++; int ans = trie_query(x, l, r); printf("%d\n", ans); } return 0;}
//2017.09.02
学习了一下oi爷的可持久化字典树,代码简短凝练(oi爷的优秀传统?),跟主席树看上去非常像,每次只更新一条链,其他的复用以前的内容,更新查询都是递归函数,都可以改写成非递归的
#include <bits/stdc++.h>using namespace std;const int N = 50000 + 10;int son[N*35][2], sum[N*35];int root[N];int tot;int len = 31;bool bs[35];//储存待处理数字的二进制表示//空树的话,所有值都是0,可以直接看作一个点,所以就直接免去了建空树的过程,要建的话,参考主席树即可void trie_insert(int p, int pre, int &x){ x = ++tot; son[x][0] = son[pre][0], son[x][1] = son[pre][1]; //memcpy(son[x], son[pre], sizeof(int) * 2); sum[x] = sum[pre] + 1; if(! p) return; trie_insert(p-1, son[pre][bs[p-1]], son[x][bs[p-1]]);}int trie_query(int p, int st, int en){//此时bs储存的是跟查询值完全相反的二进制位,即查询值要取得异或最大值所需要的二进制位 if(! p) return 0; if(sum[son[en][bs[p-1]]] > sum[son[st][bs[p-1]]]) return trie_query(p-1, son[st][bs[p-1]], son[en][bs[p-1]]) + (1<<(p-1));//此区间内在p-1位置上有需要的二进制位,就加上相应的值,并进入下一层 return trie_query(p-1, son[st][1-bs[p-1]], son[en][1-bs[p-1]]);//p-1位置上没有需要的二进制位,说明这种类型的数字不存在,只能进入另一种类型的数字中去递归查询}int main(){ int n, m, x; scanf("%d%d", &n, &m); tot = 0; for(int i = 1; i <= n; i++) { scanf("%d", &x); for(int j = len-1; j >= 0; j--) bs[j] = 1 & (x >> j); trie_insert(len, root[i-1], root[i]); } int l, r; for(int i = 1; i <= m; i++) { scanf("%d%d%d", &x, &l, &r); for(int j = len-1; j >= 0; j--) bs[j] = !(1 & (x >> j)); l++, r++; int ans = trie_query(len, root[l-1], root[r]); printf("%d\n", ans); } return 0;}
非递归版
#include <bits/stdc++.h>using namespace std;const int N = 50000 + 10;int son[N*35][2], sum[N*35];int root[N];int tot;int len = 31;bool bs[35];//void trie_insert(int p, int pre, int &x)//{// x = ++tot;// son[x][0] = son[pre][0], son[x][1] = son[pre][1];// //memcpy(son[x], son[pre], sizeof(int) * 2);// sum[x] = sum[pre] + 1;// if(! p) return;// trie_insert(p-1, son[pre][bs[p-1]], son[x][bs[p-1]]);//}//int trie_query(int p, int st, int en)//{// if(! p) return 0;// if(sum[son[en][bs[p-1]]] > sum[son[st][bs[p-1]]]) return trie_query(p-1, son[st][bs[p-1]], son[en][bs[p-1]]) + (1<<(p-1));// return trie_query(p-1, son[st][1-bs[p-1]], son[en][1-bs[p-1]]);///}int trie_insert(int val, int pre){ int x = ++tot, t = x; for(int i = len-1; i >= 0; i--) { son[x][0] = son[pre][0], son[x][1] = son[pre][1]; sum[x] = sum[pre] + 1; int j = 1 & (val >> i); son[x][j] = ++tot; x = son[x][j], pre = son[pre][j]; } sum[x] = sum[pre] + 1; return t;}int trie_query(int val, int y, int x){ int ans = 0; for(int i = len-1; i >= 0; i--) { int j = !(1 & (val >> i)); if(sum[son[x][j]] - sum[son[y][j]]> 0) { ans |= (1 << i); x = son[x][j], y = son[y][j]; } else x = son[x][!j], y = son[y][!j]; } return ans;}int main(){ int n, m, x; scanf("%d%d", &n, &m); tot = 0; for(int i = 1; i <= n; i++) { scanf("%d", &x); root[i] = trie_insert(x, root[i-1]); } int l, r; for(int i = 1; i <= m; i++) { scanf("%d%d%d", &x, &l, &r); l++, r++; int ans = trie_query(x, root[l-1], root[r]); printf("%d\n", ans); } return 0;}
阅读全文
0 0
- 51nod 1295 XOR key 01trie(可持久化字典树坑已填)
- 51Nod——1295 XOR key(贪心+可持久化字典树)
- 可持久化Trie——51nod1295 XOR key
- 51nod 1295 XOR key(字典树)
- 51Nod 1295 (XOR key)
- 51Nod-1295-XOR key
- 51nod 1295 XOR key
- 【CodeChef-XRQRS】Xor Queries【可持久化Trie / +主席树】
- BZOJ 4546|CodeChef XRQRS|Xor Queries|可持久化Trie
- Codechef Xor Queries(可持久化字典树)
- 51nod 1295 XOR key
- HDU 4757 可持久化字典树(Trie)
- 可持久化trie
- 可持久化01Trie [Heoi2013]Alo
- HDU4825 - Xor Sum(Trie 字典树)
- [BZOJ3261]-可持久化trie
- 可持久化字典树
- bzoj 3261 (可持久化trie树)
- [初学笔记]数组
- 脚本中动态添加摄像机和灯光
- Android TV Metro界面
- TensorFlow 入门
- 哪个国家拥有全世界最牛逼的程序员?
- 51nod 1295 XOR key 01trie(可持久化字典树坑已填)
- 关于进制的题
- 物联网感知层进入技术创新爆发期
- 【难容异见,常被他人的言行激怒】…
- Linux安装PHP curl拓展
- MySQL性能优化总结
- 【如果不时时和恋人黏在一起,我就…
- setTimeout经典案例
- 【明明有很多朋友,为什么还是寂寞…