uoj.#659【ULR #2】Picks loves segment tree IX 做题记录
神奇题,主要理解一下按位划分阶段的思想。link
假定 \(v = 0\),我们观察其第 \(t\) 位的值。当某次 \(+1\) 影响到该位时,视作取反。
观察某次 \(+1\),发现其会将末尾 \(k\) 位 \(1\) 全部变成 \(0\),这样容易构造出可表示的状态。
具体的,现在需要找到第一个影响到第 \(t\) 位的 \(+1\) 操作:
-
先找到第一个影响到第 \(t - 1\) 位的 \(+1\) 操作,这是子问题。
-
若在该次 \(+1\) 之前第 \(t - 1\) 位为 \(1\),那么 \(+1\) 后将影响第 \(t\) 位。
-
若在该次 \(+1\) 之前第 \(t - 1\) 位为 \(0\),那么我们重复上述过程,直到第 \(t - 1\) 位向第 \(t\) 位进位。
具体的,设 \(f_{i, j}\) 表示从操作 \(i\) 开始,首次影响到第 \(j\) 位的 \(+1\) 操作的位置,设 \(g_{i, j}\) 表示从操作 \(i\) 开始,第 \(j\) 位初始为 \(0\),首次影响到第 \(j\) 位并使其向 \(j + 1\) 位进位的 \(+1\) 操作的位置。其中第 \(0\gets j - 1\) 的初值都为 \(0\)。
为了方便,令 \(f_{i, j} \gets f_{i, j} + 1, \ g_{i, j} \gets g_{i, j} + 1\)。
若在 \(i\sim f_{i, j - 1}\) 的操作后第 \(j - 1\) 位向第 \(j\) 位进位,则 \(f_{i, j} = f_{i, j - 1}\),否则 \(f_{i, j} = g_{f_{i, j - 1}, j - 1}\)。
若在 \(i\sim f_{i, j}\) 的操作后第 \(j\) 位初始为 \(0\),最后向 \(j + 1\) 位进位,则 \(g_{i, j} = f_{i, j}\),否则 \(g_{i, j} = g_{f_{i, j}, j}\)。
然后我们只需要不断跳 \(f_{p, t}\) 就好了,可以倍增。当 \(v > 0\) 时,需要先算出第一次影响第 \(t\) 位的 \(+1\) 操作的位置,具体求法与 \(f\) 类似。
点击查看代码
#include <bits/stdc++.h>
namespace Initial {
#define ll int
#define ull unsigned ll
#define fi first
#define se second
#define mkp make_pair
#define pir pair <ll, ll>
#define pb push_back
#define i128 __int128
using namespace std;
const ll maxn = 4e5 + 10, inf = 1e9, mod = 998244353, iv = mod - mod / 2;
ll power(ll a, ll b = mod - 2, ll p = mod) {
ll s = 1;
while(b) {
if(b & 1) s = 1ll * s * a %p;
a = 1ll * a * a %p, b >>= 1;
} return s;
}
template <class T>
const inline ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
template <class T>
const inline void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
template <class T>
const inline void chkmax(T &x, const T y) { x = x < y? y : x; }
template <class T>
const inline void chkmin(T &x, const T y) { x = x < y? x : y; }
} using namespace Initial;
namespace Read {
char buf[1 << 22], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
template <class T>
const inline void rd(T &x) {
char ch; bool neg = 0;
while(!isdigit(ch = getchar()))
if(ch == '-') neg = 1;
x = ch - '0';
while(isdigit(ch = getchar()))
x = (x << 1) + (x << 3) + ch - '0';
if(neg) x = -x;
}
} using Read::rd;
ll n, m, typ; ull a[maxn]; char op[maxn];
ll f[maxn][32], g[maxn][32], key, pw, d[maxn][32][20];
bool e[maxn][32][20][2];
struct Data {
ull cov0, cov1, rev;
ll get(ll c, ll u) {
if(cov0 & (1u << u)) return 0;
if(cov1 & (1u << u)) return 1;
return (c ^ (rev >> u)) & 1;
}
} F[maxn][32], G[maxn][32], w[maxn];
const Data operator + (const Data A, const Data B) {
Data C = {};
C.rev = (A.rev ^ B.rev) & ~A.cov0 & ~A.cov1 & ~B.cov0 & ~B.cov1;
C.cov0 = (A.cov0 & ~B.rev & ~B.cov1) | (A.cov1 & B.rev & ~B.cov1) | B.cov0;
C.cov1 = (A.cov1 & ~B.rev & ~B.cov0) | (A.cov0 & B.rev & ~B.cov0) | B.cov1;
return C;
}
struct SGT {
Data t[maxn << 2];
void build(ll p, ll l, ll r) {
if(l == r) return t[p] = w[l], void();
ll mid = l + r >> 1;
build(p << 1, l, mid), build(p << 1|1, mid + 1, r);
t[p] = t[p << 1] + t[p << 1|1];
}
Data query(ll p, ll l, ll r, ll ql, ll qr) {
if(ql <= l && r <= qr) return t[p];
ll mid = l + r >> 1;
if(qr <= mid) return query(p << 1, l, mid, ql, qr);
if(mid < ql) return query(p << 1|1, mid + 1, r, ql, qr);
return query(p << 1, l, mid, ql, qr) + query(p << 1|1, mid + 1, r, ql, qr);
}
} tr;
ll as(ll x) { key = (key + typ * pw * x) %mod, add(pw, pw); return x; }
int main() {
rd(n), rd(m), rd(typ);
for(ll i = 1; i <= n; i++) {
scanf("%s", op + i), rd(a[i]);
if(op[i] == '|') w[i].cov1 = a[i];
if(op[i] == '&') w[i].cov0 = ~a[i];
if(op[i] == '^') w[i].rev = a[i];
} tr.build(1, 1, n);
for(ll i = n, lst = -1; i; i--) {
if(op[i] == '+') lst = i;
f[i][0] = lst + 1;
if(lst > 0) {
if(i < lst) F[i][0] = w[i] + F[i + 1][0];
if(!F[i][0].get(1, 0)) {
g[i][0] = g[f[i][0]][0];
if(g[i][0]) G[i][0] = F[i][0] + G[f[i][0]][0];
} else g[i][0] = f[i][0], G[i][0] = F[i][0];
}
for(ll j = 1; j < 32; j++) {
if(!f[i][j - 1]) break;
if(F[i][j - 1].get(0, j - 1)) f[i][j] = f[i][j - 1], F[i][j] = F[i][j - 1];
else f[i][j] = g[f[i][j - 1]][j - 1], F[i][j] = F[i][j - 1] + G[f[i][j - 1]][j - 1];
if(f[i][j]) {
if(F[i][j].get(1, j)) g[i][j] = f[i][j], G[i][j] = F[i][j];
else g[i][j] = g[f[i][j]][j], G[i][j] = F[i][j] + G[f[i][j]][j];
}
}
} pw = 1;
for(ll i = n; i; i--)
for(ll j = 0; j < 32; j++) {
d[i][j][0] = f[i][j];
e[i][j][0][0] = F[i][j].get(0, j) ^ 1;
e[i][j][0][1] = F[i][j].get(1, j) ^ 1;
for(ll k = 1; k < 20; k++)
d[i][j][k] = d[d[i][j][k - 1]][j][k - 1],
e[i][j][k][0] = e[d[i][j][k - 1]][j][k - 1][e[i][j][k - 1][0]],
e[i][j][k][1] = e[d[i][j][k - 1]][j][k - 1][e[i][j][k - 1][1]];
}
while(m--) {
ull v, _l, _r, _t; ll l, r, t;
rd(v), rd(_l), rd(_r), rd(_t);
v += key;
l = min((_l ^ key) % n, (_r ^ key) % n) + 1;
r = max((_l ^ key) % n, (_r ^ key) % n) + 1;
t = (_t ^ key) % 32;
ll p = f[l][0]; Data now = F[l][0];
for(ll i = 1; i <= t; i++)
if(!now.get((v >> i - 1) & 1, i - 1))
now = now + G[p][i - 1], p = g[p][i - 1];
if(!p || p > r + 1) {
Data seg = tr.query(1, 1, n, l, r);
printf("%d", as(seg.get((v >> t) & 1, t)));
continue;
}
ll c = now.get((v >> t) & 1, t) ^ 1;
for(ll i = 19; ~i; i--)
if(d[p][t][i] && d[p][t][i] <= r + 1) c = e[p][t][i][c], p = d[p][t][i];
Data seg = p <= r? tr.query(1, 1, n, p, r) : (Data) {};
printf("%d", as(seg.get(c, t)));
}
return 0;
}

浙公网安备 33010602011771号