Vexoben
Mar 12, 2019
题目链接:ZJOI2017 树状数组
签到题都不会做,真是太菜了啊。
(刷新以获取数学公式)
题意
太长不想写了,点到UOJ里面看吧……
题解
直观猜测这个树状数组可能是维护后缀和的,本地打了个代码跑了跑发现确实是这样。
询问时真实答案是,而算出来的是,注意这里加法是膜意义下的,也即是,所以只要算即可。
一开始想的是把一个询问看做一个平面上的点,点权是。那么一个修改就是对平面上三个区域做矩形乘一个数,矩形加一个数。
发现自己并不会打这样的树套树
事实上大力对两个线段树都大力维护标记是可以做的,然而想题的时候误把空间复杂度算成
定义一个函数。的值表示,将一个概率为 ,概率为的变量以概率反转,它的值为的概率。
那么只要支持矩形一个数就好了。
把以前的代码搬出来发现自己会打了
注意要特判,这时候答案会变成
#include<bits/stdc++.h>
#define fi first
#define se second
#define R register
#define mp make_pair
#define pb push_back
#define LL long long
#define Ldb long double
#define pii pair<int, int>
using namespace std;
const int N = 1e5 + 10;
const int mod = 998244353;
template <typename T> void read(T &x) {
int f = 0;
R char c = getchar();
while (c < '0' || c > '9') f |= (c == '-'), c = getchar();
for (x = 0; c >= '0' && c <= '9'; c = getchar())
x = x * 10 - '0' + c;
if (f) x = -x;
}
int n, m, ans;
int Qpow(int x, int p) {
int ans = 1;
while (p) {
if (p & 1) ans = 1LL * ans * x % mod;
x = 1LL * x * x % mod;
p >>= 1;
}
return ans;
}
int Inv(int x) {
return Qpow(x, mod - 2);
}
void merge(int &x, int y) {
x = (1LL * x * (mod + 1 - y) + 1LL * (mod + 1 - x) * y) % mod;
}
namespace SegTree2D {
int tot;
int ch[N * 400][2], tr[N * 400], rt[N << 2];
void Update1(int &x, int l, int r, int ql, int qr, int v) {
if (!x) x = ++tot, tr[x] = 0;
if (ql <= l && r <= qr) {
merge(tr[x], v);
return;
}
int mid = (l + r) >> 1;
if (mid >= ql) Update1(ch[x][0], l, mid, ql, qr, v);
if (mid < qr) Update1(ch[x][1], mid + 1, r, ql, qr, v);
}
void Update2(int x, int l, int r, int ql, int qr, int qly, int qry, int v) {
if (ql <= l && r <= qr) {
Update1(rt[x], 0, n, qly, qry, v);
return;
}
int mid = (l + r) >> 1;
if (mid >= ql) {
Update2(x << 1, l, mid, ql, qr, qly, qry, v);
}
if (mid < qr) {
Update2(x << 1 | 1, mid + 1, r, ql, qr, qly, qry, v);
}
}
void Query1(int x, int l, int r, int pos) {
if (!x) return;
merge(ans, tr[x]);
if (l == r) return;
int mid = (l + r) >> 1;
if (mid >= pos) {
Query1(ch[x][0], l, mid, pos);
}
if (mid < pos) {
Query1(ch[x][1], mid + 1, r, pos);
}
}
void Query2(int x, int l, int r, int qx, int qy) {
Query1(rt[x], 0, n, qy);
if (l == r) return;
int mid = (l + r) >> 1;
if (mid >= qx) {
Query2(x << 1, l, mid, qx, qy);
}
if (mid < qx) {
Query2(x << 1 | 1, mid + 1, r, qx, qy);
}
}
}
using namespace SegTree2D;
int main() {
read(n); read(m);
int cnt = 0;
while (m--) {
int opt, l, r;
read(opt); read(l); read(r);
if (opt == 1) {
int p = Inv(r - l + 1); ++cnt;
Update2(1, 0, n, l, r, l, r, p * 2 % mod);
Update2(1, 0, n, 0, l - 1, l, r, p);
if (r < n) {
Update2(1, 0, n, l, r, r + 1, n, p);
}
}
if (opt == 2) {
ans = 1;
Query2(1, 0, n, l - 1, r);
if ((l == 1) && cnt & 1) ans = mod + 1 - ans;
if (ans >= mod) ans -= mod;
printf("%d\n", ans);
}
}
return 0;
}