这是链接
这题可以看做每次有 1 2 \frac {1} {2} 21执行1
操作,问 t a g tag tag数组之和的期望乘 2 p 2^p 2p( p p p是1
操作的次数)。
根据期望的线性性,单独计算出每一个节点的 t a g tag tag为 1 1 1的期望 f i f_i fi,顺便计 g i g_i gi表示 i i i到根的路径有 t a g = 1 tag=1 tag=1的概率。将 [ l , r ] [l,r] [l,r]拆分成 l o g log log个在线段树上的区间,考虑每一个区间对答案的影响,可以发现对于这个区间到根的路径上的点(不包括它本身)的 f i ← f i 2 , g i ← g i 2 f_i \gets \frac{f_i}{2},g_i \gets \frac{g_i}{2} fi←2fi,gi←2gi,临近这条路径的点的 f i ← f i + g i 2 , g i f_i \gets \frac{f_i+g_i}{2},g_i fi←2fi+gi,gi不变,而这个区间本身 f i ← f i + 1 2 f_i \gets \frac {f_i+1}{2} fi←2fi+1,其子树的 g i ← g i + 1 2 g_i \gets \frac{g_i+1}{2} gi←2gi+1。
这里的修改都是 O ( l o g ) O(log) O(log)级别,暴力修改即可。对于 g i g_i gi的维护,可以维护 g i ′ = 1 − g i g_i'=1-g_i gi′=1−gi,修改时 g i ′ ← = g i ′ 2 g_i'\gets=\frac{g_i'}{2} gi′←=2gi′
#include
using namespace std;
inline int gi()
{
char c = getchar();
while(c < '0' || c > '9') c = getchar();
int sum = 0;
while('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
typedef long long ll;
const int maxn = 100005, mod = 998244353;
int n, m, P = 1, inv[maxn], f[maxn << 2], g[maxn << 2], lzy[maxn << 2], ans;
#define mid ((l + r) >> 1)
#define lch (s << 1)
#define rch (s << 1 | 1)
void build(int s, int l, int r)
{
g[s] = 1;
if (l == r) return ;
build(lch, l, mid);
build(rch, mid + 1, r);
}
inline void mdf_f(int x, int v) {ans = (ans - f[x] + mod) % mod; f[x] = (ll)(f[x] + v) * inv[1] % mod; ans = (ans + f[x]) % mod;}
inline void mdf_g(int x, int v) {g[x] = (ll)g[x] * inv[v] % mod; lzy[x] += v;}
inline void push_down(int s)
{
if (!lzy[s]) return ;
mdf_g(lch, lzy[s]); mdf_g(rch, lzy[s]);
lzy[s] = 0;
}
void modify(int s, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr) return mdf_f(s, 1), mdf_g(s, 1), void();
push_down(s);
if (ql <= mid) modify(lch, l, mid, ql, qr);
else mdf_f(lch, mod + 1 - g[lch]);
if (mid < qr) modify(rch, mid + 1, r, ql, qr);
else mdf_f(rch, mod + 1 - g[rch]);
mdf_f(s, 0); g[s] = (ll)(g[s] + 1) * inv[1] % mod;
}
int main()
{
n = gi(); m = gi();
inv[0] = 1; inv[1] = (mod + 1) >> 1;
for (int i = 2; i <= n; ++i) inv[i] = (ll)inv[i - 1] * inv[1] % mod;
build(1, 1, n);
for (int op, l, r, i = 1; i <= m; ++i) {
op = gi();
if (op == 1) l = gi(), r = gi(), P = (P << 1) % mod, modify(1, 1, n, l, r);
else printf("%lld\n", (ll)ans * P % mod);
}
return 0;
}