珂朵莉树

珂朵莉树,简称 odt,又称老司机树,用于区间推平或数据随机。其思想暴力,实现简单,名字好听,深受 OIer 喜爱。

CF896C Willem, Chtholly and Seniorious

区间推平会使最后的序列变成一段一段连续的数,那我们记一个结构体,保存每一段的端点极其权值,按左端点从小到大排序。

珂朵莉树核心是 splitassign 函数,用来分裂和合并。

split(x) 的意思是以 x 做切割,找到一个含有 x 的区间 [l,r],将其分裂为 [l,x1][x,r]。如果 x 本身就是一个区间的开头,就不用切割了,直接返回这个区间。

assign 则是合并。我们可以把整个 set 中所有要被合并掉的都删掉,然后插入一个新区间表示推平以后的结果。

#include <bits/stdc++.h> #define int long long using namespace std; const int N = 1e5 + 100; const int Mod = 1000000007; int n, m, seed, vmax, a[N]; struct odt { int l, r; mutable int v; odt(int l, int r = 0, int v = 0) : l(l), r(r), v(v) {} const bool operator < (const odt &e) const { return l < e.l; } }; set<odt> s; set<odt>::iterator split(int x) { auto it = s.lower_bound(odt(x)); if (it != s.end() && it -> l == x) return it; it--; if (it -> r < x) return s.end(); 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, int x) { set<odt>::iterator itr = split(r + 1), itl = split(l); s.erase(itl, itr), s.insert(odt(l, r, x)); } void add(int l, int r, int x) { set<odt>::iterator itr = split(r + 1), itl = split(l); for (auto it = itl; it != itr; it++) it -> v += x; } int qpow(int a, int b, int mod) { if (!b) return 1; int tmp = qpow(a, b / 2, mod); if (b & 1) return tmp % mod * tmp % mod * a % mod; return tmp % mod * tmp % mod; } struct Node { int num, cnt; bool operator < (const Node &e) const { return num < e.num; } Node(int num, int cnt) : num(num), cnt(cnt) {} }; int rnk(int l, int r, int x) { set<odt>::iterator itr = split(r + 1), itl = split(l); vector<Node> v; for (auto it = itl; it != itr; it++) { v.push_back(Node(it -> v, it -> r - it -> l + 1)); } sort(v.begin(), v.end()); int i; for (i = 0; i < v.size(); i++) { if (v[i].cnt < x) x -= v[i].cnt; else break; } return v[i].num; } int getsum(int l, int r, int x, int y) { set<odt>::iterator itr = split(r + 1), itl = split(l); int ans = 0; for (auto it = itl; it != itr; it++) { ans = (ans + qpow(it -> v % y, x, y) * (it -> r - it -> l + 1) % y) % y; } return ans; } int rnd() { int ret = seed; seed = (seed * 7 + 13) % Mod; return ret; } signed main() { cin >> n >> m >> seed >> vmax; for (int i = 1; i <= n; i++) { a[i] = (rnd() % vmax) + 1; s.insert(odt(i, i, a[i])); } for (int i = 1, x, y; i <= m; i++) { int opt = (rnd() % 4) + 1, l = (rnd() % n + 1), r = (rnd() % n + 1); if (l > r) swap(l, r); if (opt == 3) x = (rnd() % (r - l + 1)) + 1; else x = (rnd() % vmax) + 1; if (opt == 4) y = (rnd() % vmax) + 1; if (opt == 1) add(l, r, x); if (opt == 2) assign(l, r, x); if (opt == 3) cout << rnk(l, r, x) << '\n'; if (opt == 4) cout << getsum(l, r, x, y) << '\n'; } return 0; }

CF1423G Growing flowers

看到区间推平,果断珂朵莉。

对于一段长为 x 的极长连续段,对于答案的贡献是 max(0,xk+1),线段树维护即可。


__EOF__

本文作者ようこそ!
本文链接https://www.cnblogs.com/ydq1101/p/18698822.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   ydq1101  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示