选数异或(用线段树查询区间最值)
问题描述
给定一个长度为 �n 的数列 �1,�2,⋯,��A1,A2,⋯,An 和一个非负整数 �x, 给定 �m 次查 询, 每次询问能否从某个区间 [�,�][l,r] 中选择两个数使得他们的异或等于 �x 。
输入格式
输入的第一行包含三个整数 �,�,�n,m,x 。
第二行包含 �n 个整数 �1,�2,⋯,��A1,A2,⋯,An 。
接下来 �m 行,每行包含两个整数 ��,��li,ri 表示询问区间 [��,��][li,ri] 。
输出格式
对于每个询问, 如果该区间内存在两个数的异或为 �x 则输出 yes, 否则输出 no。
样例输入
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3
样例输出
yes
no
yes
no
样例说明
显然整个数列中只有 22, 33 的异或为 11。
评测用例规模与约定
对于 2020 的评测用例, 1≤�,�≤1001≤n,m≤100;
对于 4040 的评测用例, 1≤�,�≤10001≤n,m≤1000;
对于所有评测用例, 1≤�,�≤100000,0≤�<220,1≤��≤��≤�1≤n,m≤100000,0≤x<220,1≤li≤ri≤n, 0≤��<2200≤Ai<220 。
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
一般查询(最后几组会超时)
#include<bits/stdc++.h> using namespace std; const int maxn = 100000 + 10; int Left[maxn], pos[(1 << 20) + 10]; int a[maxn], n, m, x; int main() { cin >> n >> m >> x; for(int i = 1; i <= n; i++) { cin >> a[i]; Left[i] = pos[a[i] ^ x]; pos[a[i]] = i; } while(m--) { int l, r; cin >> l >> r; int t=0; for(int i=l;i<=r;i++) { if(Left[i]>t) t=Left[i]; } if(t>= l) cout<<"yes"<<endl; else cout<<"no"<<endl; } return 0; }
线段树查询(转换为区间最值查询问题) 查询区间最大值
注意tree数组下标从0开始存
例子:2 3 2 3
Left 0 1 2 3
tree 3 1 3 0 1 2 3
3
1 3
0 1 2 3
附带输出函数过程
#include<bits/stdc++.h> using namespace std; const int maxn = 100000 + 10; int tree[maxn << 2]; int Left[maxn], pos[(1 << 20) + 10]; int a[maxn], n, m, x; //线段树模板 //1 1 n void build(int o, int l, int r) { if(l == r) { tree[o] = Left[l]; cout<<"tree["<<o<<"]"<<"=Left["<<l<<"]"<<endl; return; } int mid = (l + r) >> 1; cout<<"build("<<(o<<1)<<","<<l<<","<<mid<<")"<<endl; build(o << 1, l, mid); cout<<"build("<<(o<<1|1)<<","<<mid+1<<","<<r<<")"<<endl; build(o << 1 | 1, mid + 1, r); cout<<"tree["<<o<<"]"<<"=max(tree["<<(o<<1)<<"],tree["<<(o<<1|1)<<"])"<<endl; tree[o] = max(tree[o << 1], tree[o << 1 | 1]); } //查询区间[L,R]的最大值 //1 1 n l r int query(int o, int l, int r, int L, int R) { if(L <= l && r <= R) { cout<<"return tree["<<o<<"]\n"; return tree[o]; } int mid = (l + r) >> 1; int ans = 0; cout<<L<<" "<<mid<<" "<<R<<endl; if(L <= mid) { ans = max(ans, query(o << 1, l, mid, L, R)); } if(R > mid) { ans = max(ans, query(o << 1 | 1, mid + 1, r, L, R));//找最大的left[idx] } cout<<"return "<<ans<<endl; return ans; } int main() { cin >> n >> m >> x; for(int i = 1; i <= n; i++) //预处理Left数组 { cin >> a[i]; Left[i] = pos[a[i] ^ x]; pos[a[i]] = i; } cout<<"Left\n"; for(int i=1;i<=8;i++) { cout<<Left[i]<<" "; } cout<<endl; build(1, 1, n);//线段树建树 while(m--) { int l, r; cin >> l >> r; if(query(1, 1, n, l, r) >= l)//查询区间最值 cout<<"yes"<<endl; else cout<<"no"<<endl; } cout<<"tree\n"; for(int i=1;i<=8;i++) { cout<<tree[i]<<" "; } return 0; }
例题:线段树查询区间最大值
查询数组下标为i+1到j+1的最大值
#include<bits/stdc++.h> using namespace std; const int maxn = 100000 + 10; int tree[maxn << 2]; int Left[maxn], pos[(1 << 20) + 10]; int a[maxn], n, m, x; //线段树模板 void build(int o, int l, int r) { if(l == r) { tree[o] = a[l]; return; } int mid = (l + r) >> 1; build(o << 1, l, mid); build(o << 1 | 1, mid + 1, r); tree[o] = max(tree[o << 1], tree[o << 1 | 1]); } //查询区间[L,R]的最大值 int query(int o, int l, int r, int L, int R) { if(L <= l && r <= R)return tree[o]; int mid = (l + r) >> 1; int ans = 0; if(L <= mid)ans = max(ans, query(o << 1, l, mid, L, R)); if(R > mid)ans = max(ans, query(o << 1 | 1, mid + 1, r, L, R)); return ans; } int main() { cin >> n >> m; for(int i = 1; i <= n; i++) { cin >> a[i]; } build(1, 1, n);//线段树建树 cout<<"tree"<<endl; // for(int i=1;i<2*n;i++) // cout<<tree[i]<<" "; // cout<<endl; while(m--) { int l, r; cin >> l >> r; cout<<query(1,1,n,l,r)<<endl;//输出查询到的最大值 } return 0; }
查询最小值
#include<bits/stdc++.h> using namespace std; const int maxn = 100000 + 10; int tree[maxn << 2]; int a[maxn], n,m; //线段树模板 void build(int o, int l, int r) { if(l == r) { tree[o] = a[l]; return; } int mid = (l + r) >> 1; build(o << 1, l, mid); build(o << 1 | 1, mid + 1, r); tree[o] = min(tree[o << 1], tree[o << 1 | 1]); } //查询区间[L,R]的最小值 int query(int o, int l, int r, int L, int R) { if(L <= l && r <= R)return tree[o]; int mid = (l + r) >> 1; int ans = 999999;//查询最小值 if(L <= mid)ans = min(ans, query(o << 1, l, mid, L, R)); if(R > mid)ans = min(ans, query(o << 1 | 1, mid + 1, r, L, R)); return ans; } int main() { cin >> n>>m; for(int i = 1; i <= n; i++) { cin >> a[i]; } build(1, 1, n);//线段树建树 // cout<<"tree"<<endl; // for(int i=1;i<2*n;i++) // cout<<tree[i]<<" "; // cout<<endl; while(m--) { int l, r; cin >> l >> r; cout<<query(1,1,n,l,r)<<endl;//输出查询到的最小值 } return 0; }