知识点总结:
可持久化数据结构,适合不断添加数,并且便添加边查找区间信息的问题。数据范围在1e5以上
256. 最大异或和
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 600010, M = 25 * N;
int n, m;
int s[N]; // 代表前n个数的异或前缀和
int tr[M][2], max_id[M]; // tr 存储的是结点编号 max_id 存储的是当前数字的最大下标
int root[N], idx; // root存储的是根节点的编号 idx 是动态分配的编号最大值
void insert(int k, int p, int q) // k 当前的结点编号 p 上一个状态的根节点的编号 q 这次需要插入的根节点的编号
{
max_id[q] = k;
for (int i = 23; i >= 0; i -- )
{
int v = s[k] >> i & 1;
if (p) tr[q][1 ^ v] = tr[p][1 ^ v]; // 相对的分支直接复制
tr[q][v] = ++ idx;
max_id[tr[q][v]] = k;
q = tr[q][v], p = tr[p][v];
}
}
int query(int p, int l, int c) // root 是根节点对应的编号 l 左边界 c 计算的值
{
for (int i = 23; i >= 0; i -- )
{
int v = c >> i & 1;
if (max_id[tr[p][v ^ 1]] >= l) p = tr[p][v ^ 1];
else p = tr[p][v];
}
return c ^ s[max_id[p]];
}
int main()
{
scanf("%d%d", &n, &m);
s[0] = 0;
max_id[0] = -1;
root[0] = ++ idx;
insert(0, 0, root[0]); // 当前的最大位置 前一个状态 当前的状态
for (int i = 1; i <= n; i ++ )
{
int x;
scanf("%d", &x);
root[i] = ++ idx;
s[i] = s[i - 1] ^ x;
insert(i, root[i - 1], root[i]);
}
char op[2];
int l, r, x;
while (m -- )
{
scanf("%s", op);
if (*op == 'A')
{
scanf("%d", &x);
++ n;
s[n] = s[n - 1] ^ x;
root[n] = ++ idx;
insert(n, root[n - 1], root[n]);
}
else
{
scanf("%d %d %d", &l, &r, &x);
printf("%d\n", query(root[r - 1], l - 1, s[n] ^ x)); // 计算的范围是l~r,但是为了找p的范围
}
}
return 0;
}
255. 第K小数
/*
*
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 100010;
int n, m;
int a[N];
struct Node
{
int l, r;
int cnt;
}tr[N * 4 + N * 17];
vector<int> nums;
int root[N], idx;
int find(int x)
{
return lower_bound(nums.begin(), nums.end(), x) - nums.begin();
}
int build(int l, int r)
{
int p = ++ idx;
if (l == r) return p;
int mid = l + r >> 1;
tr[p].l = build(l, mid), tr[p].r = build(mid + 1, r);
return p;
}
int insert(int p, int l, int r, int x)
{
int q = ++ idx;
tr[q] = tr[p];
if (l == r)
{
tr[q].cnt ++ ;
return q;
}
int mid = l + r >> 1;
if (x <= mid) tr[q].l = insert(tr[p].l, l, mid, x);
else tr[q].r = insert(tr[p].r, mid + 1, r, x);
tr[q].cnt = tr[tr[q].l].cnt + tr[tr[q].r].cnt;
return q;
}
int query(int q, int p, int l, int r, int k)
{
if(l == r) return r;
int cnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt;
int mid = l + r >> 1;
if (k <= cnt) return query(tr[q].l, tr[p].l, l, mid, k);
else return query(tr[q].r, tr[p].r, mid + 1, r, k - cnt);
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &a[i]);
nums.push_back(a[i]);
}
sort(nums.begin(), nums.end());
nums.erase(unique(nums.begin(), nums.end()), nums.end());
root[0] = build(0, nums.size() - 1);
for (int i = 1; i <= n; i ++ )
root[i] = insert(root[i - 1], 0, nums.size() - 1, find(a[i]));
while (m -- )
{
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
printf("%d\n", nums[query(root[r], root[l - 1], 0, nums.size() - 1, k)]);
}
return 0;
}