「解题报告」UOJ671 [UNR #5] 诡异操作
这题怎么这么多差评啊?哦卡常啊,没事了。
发现两个操作都是只增不减,显然势能线段树。
考虑维护区间按位与,线段树上维护每一位上有多少个
考虑优化。注意到叶子处的数都很小,即数很多而值域很小。那么我们考虑按照值域维护,而不是按照每一位维护。我们将出现次数的每一位维护一个 int128
,合并时可以直接模拟二进制加法,区间赋 pushUp
的复杂度变为了
具体来讲,就是考虑势能线段树的分析方法。简单设一个节点的势能函数为当前区间内 pushUp
复杂度为 或打表可知
于是总复杂度就是
然后 注 意 常 数 优 化 。(比如不要维护区间和,等查询的时候再直接求;用 vector
减少内存不连续访问)
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 600005;
typedef __uint128_t u128;
const u128 UINT128_MAX = ((u128) ULLONG_MAX << 64 | ULLONG_MAX);
inline u128 read() {
static char buf[100];
scanf("%s", buf);
u128 res = 0;
for (int i = 0; buf[i]; ++i) {
res = res << 4 | (buf[i] <= '9' ? buf[i] - '0' : buf[i] - 'a' + 10);
}
return res;
}
inline void output(u128 res) {
if (res >= 16)
output(res / 16);
putchar(res % 16 >= 10 ? 'a' + res % 16 - 10 : '0' + res % 16);
}
int n, q;
u128 a[MAXN];
vector<u128> val[MAXN << 2];
u128 tag[MAXN << 2];
bool empty[MAXN << 2];
#define lc (i << 1)
#define rc (i << 1 | 1)
__attribute__((always_inline)) inline void pushUp(int i) {
u128 x = 0;
auto &o = val[i], &p = val[lc], &q = val[rc];
empty[i] = empty[lc] && empty[rc];
for (int j = 0; j < p.size(); j++) {
o[j] = p[j] ^ q[j] ^ x;
x = (p[j] & x) | (q[j] & x) | (p[j] & q[j]);
}
o[p.size()] = x;
}
__attribute__((always_inline)) inline void addTag(int i, u128 x) {
tag[i] &= x;
for (int j = 0; j < val[i].size(); j++) val[i][j] &= x;
}
__attribute__((always_inline)) inline void pushDown(int i) {
while (~tag[i])
addTag(lc, tag[i]), addTag(rc, tag[i]), tag[i] = UINT128_MAX;
}
void build(int i = 1, int l = 1, int r = n) {
tag[i] = UINT128_MAX;
if (l == r) {
val[i].push_back(a[l]);
empty[i] = val[i][0] == 0;
return;
}
int mid = (l + r) >> 1;
build(lc, l, mid), build(rc, mid + 1, r);
val[i].resize(val[lc].size() + 1);
pushUp(i);
}
void updateAnd(int qa, int qb, u128 qv, int i = 1, int l = 1, int r = n) {
if (empty[i]) return;
if (qa <= l && r <= qb) {
addTag(i, qv);
return;
}
int mid = (l + r) >> 1;
pushDown(i);
if (qa <= mid) updateAnd(qa, qb, qv, lc, l, mid);
if (qb > mid) updateAnd(qa, qb, qv, rc, mid + 1, r);
pushUp(i);
}
void updateDiv(int qa, int qb, u128 qv, int i = 1, int l = 1, int r = n) {
if (empty[i]) return;
if (l == r) {
empty[i] = (val[i][0] /= qv) == 0;
return;
}
int mid = (l + r) >> 1;
pushDown(i);
if (qa <= mid) updateDiv(qa, qb, qv, lc, l, mid);
if (qb > mid) updateDiv(qa, qb, qv, rc, mid + 1, r);
pushUp(i);
}
u128 sum(int qa, int qb, int i = 1, int l = 1, int r = n) {
if (qa <= l && r <= qb) {
u128 ret = 0;
for (int j = 0; j < val[i].size(); j++) {
ret += val[i][j] << j;
}
return ret;
}
int mid = (l + r) >> 1;
pushDown(i);
if (qb <= mid) return sum(qa, qb, lc, l, mid);
if (qa > mid) return sum(qa, qb, rc, mid + 1, r);
return sum(qa, qb, lc, l, mid) + sum(qa, qb, rc, mid + 1, r);
}
int main() {
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) {
a[i] = read();
}
int m = n; n = 1;
while (n < m) n <<= 1;
build();
while (q--) {
int op, l, r; scanf("%d%d%d", &op, &l, &r);
if (op == 1) {
u128 x = read();
if (x != 1) updateDiv(l, r, x);
} else if (op == 2) {
updateAnd(l, r, read());
} else {
output(sum(l, r)), putchar('\n');
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通