CF620E NewYearTree

题目链接

  主要要实现区间覆盖区间查询不同数,看见区间赋值操作可能会想到ODT来实现,区间查询不同数直接另外开一个数组记录一下就好了,但很可惜TLE了,代码如下:

struct ODT { struct Node { i64 l, r; mutable i64 v; Node (i64 l, i64 r = 0, i64 v = 0) : l(l), r(r), v(v) {} bool operator < (const Node& lhs) const { return l < lhs.l; } }; std::set<Node> s; std::set<Node>::iterator split(int pos) { // 分裂区间 std::set<Node>::iterator it = s.lower_bound(Node(pos)); if (it -> l == pos && it != s.end()) return it; -- it; if (it -> r < pos) return s.end(); i64 l = it -> l, r = it -> r, v = it -> v; s.erase(it); s.insert(Node(l, pos - 1, v)); return s.insert(Node(pos, r, v)).first; } void assign(int l, int r, i64 x) { //区间推平 std::set<Node>::iterator itr = split(r + 1), itl = split(l); s.erase(itl, itr); s.insert(Node(l, r, x)); } i64 query(i64 l, i64 r) { // 区间查询 auto itr = split(r + 1), itl = split(l); std::vector<int> ans(100); int res = 0; for (auto it = itl; it != itr; ++it) { if(!ans[it -> v]) res ++; ans[it -> v]++; } return res; } }; void solve() { int n, m; std::cin >> n >> m; std::vector<int> col(n + 1); for (int i = 1; i <= n; i++) std::cin >> col[i]; std::vector<int> G[n + 1]; for (int i = 1; i < n; i++) { int a, b; std::cin >> a >> b; G[a].push_back(b); G[b].push_back(a); } // siz是子树大小,son是重儿子,dep是这个节点的深度,dfn是dfs序,top是链的端点 std::vector<int> parent(n + 1), siz(n + 1), son(n + 1), dep(n + 1); std::vector<int> dfn(n + 1), top(n + 1), rnk(n + 1); int idx = 0; std::function<void(int, int, int)> dfs1 = [&] (int u, int fa, int depth) { //预处理出来轻重链 parent[u] = fa; dep[u] = depth; siz[u] = 1; for (auto v : G[u]) { if (v == fa) continue; dfs1(v, u, depth + 1); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } }; std::function<void(int, int)> dfs2 = [&] (int u, int t) -> void { //剖分 dfn[u] = ++ idx; top[u] = t; rnk[idx] = u; if (!son[u]) return ; dfs2(son[u], t); for (auto v : G[u]) { if (v == parent[u] || v == son[u]) continue; dfs2(v, v); } }; dfs1(1, 0, 1); dfs2(1, 1); ODT odt; for (int i = 1; i <= n; i++) { int ver = rnk[i]; odt.s.insert(ODT::Node(dfn[ver], dfn[ver], col[ver])); } for (int i = 0; i < m; i++) { int op, u; std::cin >> op >> u; if (op == 1) { int cc; std::cin >> cc; odt.assign(dfn[u], dfn[u] + siz[u] - 1, cc); } else { std::cout << odt.query(dfn[u], dfn[u] + siz[u] - 1) << "\n"; } } }

  既然TLE了那还是想想线段树怎么做吧,注意到数据范围只有0c60,而longlong类型的数据最多可以存63位,我们就可以通过与运算来实现对一个区间内所有的数的种类进行统计,区间查询的答案就是二进制下1的个数。

struct Seg { struct Node { int l, r; i64 val, tag; }; const int n; std::vector<Node> tr; Seg(int n) : n(n), tr(4 << std::__lg(n)) { std::function<void(int, int, int)> build = [&] (int u, int l, int r) -> void { tr[u] = {l, r}; if (l == r) return ; int mid = (l + r) >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); tr[u].val = tr[u << 1].val | tr[u << 1 | 1].val; }; build(1, 1, n); } void spread(int u, i64 x) { tr[u].val = tr[u].tag = x; } void push(int u) { if (tr[u].tag) { spread(u << 1, tr[u].tag); spread(u << 1 | 1, tr[u].tag); tr[u].tag = 0; } } void modify(int u, int pos, i64 x) { if (tr[u].l == tr[u].r && tr[u].l == pos) return void(tr[u].val = x); int mid = (tr[u].l + tr[u].r) >> 1; if (mid >= pos) modify(u << 1, pos, x); else modify(u << 1 | 1, pos, x); tr[u].val = tr[u << 1].val | tr[u << 1 | 1].val; } void change(int u, int l, int r, int x) { if (tr[u].l >= l && tr[u].r <= r) { tr[u].val = (1ll << x); tr[u].tag = (1ll << x); return ; } push(u); int mid = (tr[u].l + tr[u].r) >> 1; if (mid >= l) change(u << 1, l, r, x); if (mid < r) change(u << 1 | 1, l, r, x); tr[u].val = tr[u << 1].val | tr[u << 1 | 1].val; } i64 query(int u, int l, int r) { if (tr[u].l >= l && tr[u].r <= r) return tr[u].val; push(u); int mid = (tr[u].l + tr[u].r) >> 1; i64 ans = 0; if (mid >= l) ans |= query(u << 1, l, r); if (mid < r) ans |= query(u << 1 | 1, l, r); return ans; } }; void solve() { int n, m; std::cin >> n >> m; std::vector<int> col(n + 1); for (int i = 1; i <= n; i++) std::cin >> col[i]; std::vector<int> G[n + 1]; for (int i = 1; i < n; i++) { int a, b; std::cin >> a >> b; G[a].push_back(b); G[b].push_back(a); } // siz是子树大小,son是重儿子,dep是这个节点的深度,dfn是dfs序,top是链的端点 std::vector<int> parent(n + 1), siz(n + 1), son(n + 1), dep(n + 1); std::vector<int> dfn(n + 1), top(n + 1); std::vector<int> rnk(n + 1); int idx = 0; std::function<void(int, int, int)> dfs1 = [&] (int u, int fa, int depth) { //预处理出来轻重链 parent[u] = fa; dep[u] = depth; siz[u] = 1; for (auto v : G[u]) { if (v == fa) continue; dfs1(v, u, depth + 1); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } }; std::function<void(int, int)> dfs2 = [&] (int u, int t) -> void { //剖分 dfn[u] = ++ idx; top[u] = t; rnk[idx] = u; if (!son[u]) return ; dfs2(son[u], t); for (auto v : G[u]) { if (v == parent[u] || v == son[u]) continue; dfs2(v, v); } }; dfs1(1, 0, 1); dfs2(1, 1); Seg SGT(n + 1); for (int i = 1; i <= n; i++) { int ver = rnk[i]; SGT.modify(1, i, (1ll << col[ver])); } for (int i = 1; i <= m; i++) { int op, u; std::cin >> op >> u; if (op == 1) { int cc; std::cin >> cc; SGT.change(1, dfn[u], dfn[u] + siz[u] - 1, cc); } else { std::cout << __builtin_popcountll(SGT.query(1, dfn[u], dfn[u] + siz[u] - 1)) << "\n"; } } }

__EOF__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/16644217.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示