解题思路:
- 首先要异或第 k k k大那么肯定是和Trie树有关!!
- 而且每个区间的询问,那么肯定是可持久化的Trie树啦
- 这道题有个小 T i p s Tips Tips就是那个 n ∈ [ 1 , 1000 ] 和 q ∈ [ 1 , 500 ] n\in[1,1000]和q\in[1,500] n∈[1,1000]和q∈[1,500]
- 那么我们就可以去枚举 n n n对于每次询问
- 首先我们从高位往低位看
- 就对于高位 b b b看,我们枚举 n n n,看每个n的第 b b b位在Trie树上看与之相反的有多少相反的(就是这 n n n个数异或有多少种高位为1,因为高位权值大),那么就有点像权值线段树一样跳了,假如当前位有 c n t k cnt_k cntk个异或为1
- 看看 c n t k cnt_k cntk和 k k k的关系,如果比 k k k大就往异或为 1 1 1的跳
- 如果比 k k k小就,往异或为0跳,并且 k = k − c n t k k=k-cnt_k k=k−cntk
- 注意是 n n n个点一起跳
AC code
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
int root[maxn];
struct Trie {
int tr[maxn * 40][2], sum[maxn * 40];
int cnt;
void insert(int &now, int pre, int val) {
now = ++ cnt;
int poi = now;
for(int i = 31; i >= 0; -- i) {
tr[poi][0] = tr[pre][0];
tr[poi][1] = tr[pre][1];
sum[poi] = sum[pre] + 1;
int c = (val >> i) & 1;
pre = tr[pre][c];
tr[poi][c] = ++ cnt;
poi = tr[poi][c];
}
sum[poi] = sum[pre] + 1;
}
}trie;
int X[maxn], Y[maxn];
int out[105][2];
inline int work(int u,int d,int l,int r, int k) {
for(int i = u; i <= d; ++ i) {
out[i][0] = root[l-1];
out[i][1] = root[r];
}
int res;
int ans = 0;
for(int i = 31; i >= 0; -- i) {
int cnt = 0;
for(int j = u; j <= d; ++ j) {
int c = (X[j] >> i) & 1;
int p1 = trie.sum[ trie.tr[out[j][0]][c^1] ];
int p2 = trie.sum[ trie.tr[out[j][1]][c^1] ];
cnt += p2 - p1;// 求有多少个数异或出来第i位为1
}
if(cnt >= k) res = 1;// 决定往异或为1跳还是为0跳
else k -= cnt, res = 0;
ans = (ans<<1)|res;
for(int j = u; j <= d; ++ j) {
int c = (((X[j] >> i) & 1) ^ res);
int &now0 = out[j][0], &now1 = out[j][1];
now0 = trie.tr[now0][c];
now1 = trie.tr[now1][c];
}
}
return ans;
}
int main() {
int n, m;
read(n,m);
for(int i = 1; i <= n; ++ i) read(X[i]);
for(int j = 1; j <= m; ++ j) read(Y[j]), trie.insert(root[j],root[j-1],Y[j]);
int q;
read(q);
while(q --) {
int u, d, l, r, k;
read(u,d,l,r,k);
printf("%d\n",work(u,d,l,r,k));
}
return 0;
}
/*
31 31
1 2 4
7 6 5
1
2 31 2 31 4
*/