Loading

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;
}
posted @ 2025-02-09 15:33  Sktn0089  阅读(54)  评论(0)    收藏  举报