目录
一、题目
1、题目描述
2、输入输出
2.1输入
2.2输出
3、原题链接
二、解题报告
1、思路分析
值域是10^10,也就是34位数
根据鸽巢原理,35个数字一定有两个数有公共位
位与运算贪心原则是:与的数越多,最后的结果越小
对于一个数组b,我们如何求其最大与和?
暴力方法:枚举(i, j)对,取最大b[i] & b[j],时间复杂度O(N^2)
鸽巢原理优化:取前logU大个数,暴力枚举枚举(i, j)对,取最大b[i] & b[j],时间复杂度O(log^2 U)
题目给了512M的空间,那么我们考虑线段树来维护
每个节点维护一个长度不超过35的向量,pushup操作即归并排序取前 min(l.sz + r.sz, B) 大的
查询结果即上面对于数组的最大与和的获取
2、复杂度
时间复杂度: O(m logm logU)空间复杂度: O(m logm logU)
3、代码详解
#include <bits/stdc++.h>
// #define DEBUG
using i64 = long long;
using u32 = unsigned int;
using u64 = unsigned long long;
template <class Info, class Tag>
struct LazySegmentTree {
const int n;
std::vector<Info> info;
std::vector<Tag> tag;
LazySegmentTree(int _n) : n(_n), info(2 << (32 - __builtin_clz(n))), tag(2 << (32 - __builtin_clz(n))){}
void pull(int p) {
info[p] = info[p << 1] + info[p << 1 | 1];
}
void apply(int p, const Tag &t) {
info[p].apply(t);
tag[p].apply(t);
}
void push(int p) {
apply(p << 1, tag[p]);
apply(p << 1 | 1, tag[p]);
tag[p] = Tag();
}
template<class T>
LazySegmentTree(std::vector<T>& _init): LazySegmentTree(_init.size()) {
auto build = [&](auto&& self, int p, int l, int r) {
if (l == r) {
info[p] = { {_init[l]}, 1 };
return;
}
int mid = l + r >> 1;
self(self, p << 1, l, mid), self(self, p << 1 | 1, mid + 1, r);
pull(p);
};
build(build, 1, 0, n - 1);
}
Info rangeQuery(int p, int l, int r, int x, int y) {
if (l > y || r < x) return Info();
if (x <= l && r <= y)
return info[p];
push(p);
int mid = l + r >> 1;
return rangeQuery(p << 1, l, mid, x, y) + rangeQuery(p << 1 | 1, mid + 1, r, x, y);
}
Info rangeQuery(int l, int r) {
return rangeQuery(1, 0, n - 1, l, r);
}
void rangeApply(int p, int l, int r, int x, int y, const Tag &v){
if (l > y || r < x) return;
if (x <= l && r <= y) {
apply(p, v);
return;
}
int mid = l + r >> 1;
push(p);
rangeApply(p << 1, l, mid, x, y, v);
rangeApply(p << 1 | 1, mid + 1, r, x, y, v);
pull(p);
}
void rangeApply(int l, int r, const Tag &v) {
rangeApply(1, 0, n - 1, l, r, v);
}
};
constexpr int B = 35;
struct Tag {
i64 add = 0;
void apply(const Tag& t) {
add += t.add;
}
};
struct Info {
std::vector<i64> b;
int act = 0;
void apply(const Tag &t) {
for (i64 &x : b)
x += t.add;
}
};
Info operator + (const Info &x, const Info &y) {
int act = std::min(B, x.act + y.act);
std::vector<i64> b;
int i = 0, j = 0;
while (b.size() < act && i < x.b.size() && j < y.b.size())
if (x.b[i] > y.b[j])
b.push_back(x.b[i ++]);
else
b.push_back(y.b[j ++]);
while (b.size() < act && i < x.b.size())
b.push_back(x.b[i ++]);
while (b.size() < act && j < y.b.size())
b.push_back(y.b[j ++]);
return Info{ b, act };
}
void solve(){
int n, m;
std::cin >> n >> m;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) std::cin >> a[i];
LazySegmentTree<Info, Tag> sgt(a);
for (int i = 0, op, l, r; i < m; ++ i) {
std::cin >> op >> l >> r;
if (op == 2 && l == r) {
std::cout << -1 << '\n';
continue;
}
if (op == 1) {
i64 v;
std::cin >> v;
sgt.rangeApply(l - 1, r - 1, Tag{v});
}
else {
auto b = sgt.rangeQuery(l - 1, r - 1).b;
i64 ma = 0;
for (int i = 0; i < b.size(); ++ i)
for (int j = i + 1; j < b.size(); ++ j)
ma = std::max(ma, b[i] & b[j]);
std::cout << ma << '\n';
}
}
}
auto FIO = []{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
int main() {
#ifdef DEBUG
freopen("in.txt", 'r', stdin);
freopen("out.txt", 'w', stdout);
#endif
int t = 1;
// std::cin >> t;
while(t --)
solve();
return 0;
}