饺子醋环节。
题意:给出一个 \(n\) 长序列 \(a\),有三种操作:
-
区间除法。
-
区间取与。
-
区间求和。
\(n\le 2\times 10^5,V< 2^{128}\)。题面给了一份输入输出模板。
做法:
首先直接做考虑每个点维护一下 \(2^k\) 出现了多少次,一操作直接做总复杂度是 \(O(n\log V)\) 的,二操作采用直接打 tag,复杂度 \(O(n\log n)\),pushup 是 \(\log V\) 的,所以总复杂度是 \(O(n\log^2V)\)。
考虑怎么优化,除法和 tag 感觉没什么可以优化的了,考虑怎么优化 pushup。观察 pushup 的本质是什么,我们把 \(2^k\) 出现次数展开成二进制写,其实我们是维护了一个 \(\log V\times \log n\) 的矩阵,那么我们其实没有必要去维护 \(\log V\) 这边,而是维护 \(\log n\) 这一边即可,复杂度降到 \(n\log n\log V\),可以通过。没有太看懂网上题解对于除法说精细实现可以做到 \(n\log V\) 的解释,我一直整体除以 \(2\) 不是爆炸完了。
有点卡常,一个可行的卡常方法是把每个节点只考虑前若干个有值得行,这样会快特别多。我这里比较暴力,直接把长度补成 \(2^n\) 然后就比较方便定长度。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define u128 __uint128_t
const int maxn = 5.3e5 + 5;
typedef __uint128_t u128;
inline u128 read() {static char buf[100];scanf("%s", buf);// std::cin >> 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);//std::cout.put(res % 16 >= 10 ? 'a' + res % 16 - 10 : '0' + res % 16);
}
struct node {vector<u128> a;bool f;inline u128& operator[](int x) {return a[x];}void resize(int N) {a.resize(N);}inline int size() {return a.size();}
} ;
int n, q;
u128 a[maxn], mx, pw = 1;
int len[maxn];
struct Segtree {node tr[maxn << 2];u128 tag[maxn << 2];void pushup(int t) {tr[t].f = tr[t << 1].f & tr[t << 1 | 1].f;u128 val = 0;for (int i = 0; i < tr[t << 1].size(); i++) {tr[t][i] = val ^ tr[t << 1][i] ^ tr[t << 1 | 1][i];val = (tr[t << 1][i] & tr[t << 1 | 1][i]) | (tr[t << 1][i] & val) | (val & tr[t << 1 | 1][i]);}tr[t][tr[t].size() - 1] = val;}void build(int l, int r, int t) {tag[t] = mx;tr[t].resize(len[r - l + 1]);//cout << l << " " << r << "asdf " << len[r - l + 1] << endl;if(l == r) {tr[t][0] = a[l];tr[t].f = a[l] == 0;return ;}int mid = l + r >> 1;build(l, mid, t << 1), build(mid + 1, r, t << 1 | 1);pushup(t);}void addtag(int t, u128 val) {tag[t] &= val;for (int i = 0; i < tr[t].size(); i++)tr[t][i] &= val;}void pushdown(int t) {if(tag[t] == mx)return ;addtag(t << 1, tag[t]);addtag(t << 1 | 1, tag[t]);tag[t] = mx;}void update1(int l, int r, int x, int y, int t, u128 v) {if(tr[t].f)return ;if(l == r) {tr[t][0] /= v;tr[t].f = tr[t][0] == 0;return ;}int mid = l + r >> 1;pushdown(t);if(x <= mid)update1(l, mid, x, y, t << 1, v);if(mid < y)update1(mid + 1, r, x, y, t << 1 | 1, v);pushup(t);}void update2(int l, int r, int x, int y, int t, u128 v) {if(tr[t].f)return ;if(x <= l && r <= y) {addtag(t, v);return ;}int mid = l + r >> 1;pushdown(t);if(x <= mid)update2(l, mid, x, y, t << 1, v);if(mid < y)update2(mid + 1, r, x, y, t << 1 | 1, v);pushup(t);}u128 query(int l, int r, int x, int y, int t) {if(x <= l && r <= y) {u128 res = 0;for (int i = 0; i < tr[t].size(); i++)res += tr[t][i] << i;return res;}int mid = l + r >> 1;pushdown(t);if(y <= mid)return query(l, mid, x, y, t << 1);if(mid < x)return query(mid + 1, r, x, y, t << 1 | 1);return query(l, mid, x, y, t << 1) + query(mid + 1, r, x, y, t << 1 | 1);}
} tree;
signed main() {cin >> n >> q;for (int i = 1; i <= n; i++)a[i] = read();for (int i = 0; i < 128; i++)mx += pw, pw <<= 1;int tn = 1, cnt = 1;while(tn < n)len[tn] = cnt, tn <<= 1, cnt++;len[tn] = cnt;n = tn;tree.build(1, n, 1);while(q--) {int op, l, r; u128 v;cin >> op >> l >> r;if(op == 1) {v = read();if(v != 1)tree.update1(1, n, l, r, 1, v);}if(op == 2)v = read(), tree.update2(1, n, l, r, 1, v);if(op == 3)output(tree.query(1, n, l, r, 1)), putchar('\n');}return 0;
}