题解 CF981G Magic multisets
题意
给定
-
下标在
的可重集加入数 -
查询下标在
的可重集大小的和,对 取模。
数据范围:
题解
这个题跟 P8416 处理方法有点像。
有
这个问题相当于给定一个序列,加入数
这种区间推平问题很自然地想到颜色段均摊,即 ODT。
有个很经典的 trick 就是用 ODT 把区间推平转成区间加。
于是我们开
这个题可以先把区间的集合大小乘
然后这个复杂度的正确性,因为颜色段均摊每次 split
最多增加
注意 split
要先分裂
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inv2 = mod + 1 >> 1;
int n, q;
namespace segment_tree {
#define ls x << 1
#define rs x << 1 | 1
int tagm[N << 2], taga[N << 2], sum[N << 2];
void build(int x, int l, int r) {
if(l == r) return;
int mid = l + r >> 1;
taga[x] = 0, tagm[x] = 1;
build(ls, l, mid), build(rs, mid + 1, r);
}
void pushup(int x) { sum[x] = (sum[ls] + sum[rs]) % mod; }
void pusha(int x, int l, int r, int v) {
if(!v) return;
taga[x] = (taga[x] + v) % mod;
sum[x] = (sum[x] + 1ll * (r - l + 1) * v) % mod;
}
void pushm(int x, int v) {
if(v == 1) return;
tagm[x] = 1ll * tagm[x] * v % mod;
taga[x] = 1ll * taga[x] * v % mod;
sum[x] = 1ll * sum[x] * v % mod;
}
void pushdown(int x, int l, int r) {
int mid = l + r >> 1;
pushm(ls, tagm[x]), pushm(rs, tagm[x]);
tagm[x] = 1;
pusha(ls, l, mid, taga[x]), pusha(rs, mid + 1, r, taga[x]);
taga[x] = 0;
}
void updatea(int x, int l, int r, int L, int R, int v) {
if(L <= l && r <= R) { pusha(x, l, r, v); return; }
pushdown(x, l, r);
int mid = l + r >> 1;
if(mid >= L) updatea(ls, l, mid, L, R, v);
if(mid < R) updatea(rs, mid + 1, r, L, R, v);
pushup(x);
}
void updatem(int x, int l, int r, int L, int R, int v) {
if(L <= l && r <= R) { pushm(x, v); return; }
pushdown(x, l, r);
int mid = l + r >> 1;
if(mid >= L) updatem(ls, l, mid, L, R, v);
if(mid < R) updatem(rs, mid + 1, r, L, R, v);
pushup(x);
}
int query(int x, int l, int r, int L, int R) {
if(L <= l && r <= R) return sum[x];
pushdown(x, l, r);
int mid = l + r >> 1, res = 0;
if(mid >= L) res = (res + query(ls, l, mid, L, R)) % mod;
if(mid < R) res = (res + query(rs, mid + 1, r, L, R)) % mod;
return res;
}
} using namespace segment_tree;
struct old_driver_tree {
struct odt {
int l, r;
mutable int v;
odt(int L = 0, int R = 0, int V = 0) { l = L, r = R, v = V; }
friend bool operator < (const odt &qwq, const odt &awa) {
return qwq.l < awa.l;
}
};
set<odt> s;
void init() { s.insert(odt(1, n)); }
#define IT set<odt>::iterator
#define pii pair<int, int>
IT split(int x) {
IT it = s.lower_bound(odt(x, 0, 0));
if(it != s.end() && it -> l == x) return it;
--it;
int L = it -> l, R = it -> r, V = it -> v;
s.erase(it);
s.insert(odt(L, x - 1, V));
return s.insert(odt(x, R, V)).first;
}
void assign(int l, int r) {
updatem(1, 1, n, l, r, 2);
IT itr = split(r + 1), itl = split(l);
for(IT it = itl; it != itr; ++it)
if(!(it -> v))
updatem(1, 1, n, it -> l, it -> r, inv2),
updatea(1, 1, n, it -> l, it -> r, 1);
s.erase(itl, itr);
s.insert(odt(l, r, 1));
}
} t[N];
int main() {
scanf("%d%d", &n, &q);
build(1, 1, n);
for(int i = 1; i <= n; i++)
t[i].init();
while(q--) {
int opt, l, r, x;
scanf("%d%d%d", &opt, &l, &r);
if(opt == 1) {
scanf("%d", &x);
t[x].assign(l, r);
}
else printf("%d\n", query(1, 1, n, l, r));
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话