当前位置: 首页 > news >正文

CF2115F2 Gellyfish and Lycoris Radiata (Hard Version)

很厉害的 DS 题,记一下 qiuzx 的做法。

考虑到每次操作实际上只会增加 \(O(1)\) 个连续段,一个想法是对时间轴建线段树,在两个子节点已知时合并父节点,合并两个节点可以 \(O(len\log len)\) 解决,此处的总复杂度是 \(O(q\log^2 q)\) 的。

于是我们解决了 reverse,考虑一下 insert 和 delete。因为 insert 实际上代表的是那一次修改是否对 \(p\) 有影响,所以我们实际上就是要去找第一次修改的时刻,所以可以对每个连续段维护线段树节点管辖的区间内是否存在修改,然后容易线段树上二分解决。

再来考虑 delete 怎么做。根据上面,我们只要修改对应是否修改的标记 flag 即可,如果一个连续段的标记被清空,就向上考虑父节点处其归并出来的段。因为每段只会被从左右的两个段各考虑一次,所以这部分的复杂度是 \(O(q\log q)\) 的。

那么总复杂度就做到了 \(O(q\log^2 q)\)

#include <bits/stdc++.h>
using namespace std;const int kN = 3e5 + 5, kS = kN * 4, kC = kN * 40;
int n, q, c;struct Node {int l, r, p, q;int flag;bool rev;
} node[kC];
vector<int> nxt[kC];struct Query {int o, l, r, p;
};#define ls (o << 1)
#define rs (o << 1 | 1)struct SGT {vector<int> info[kS], vec[kS];void Up(int o) {if(info[rs].empty()) return ;for(int i : info[ls]) {Node nd = node[i];int cl = nd.l, cr = nd.r;int p = nd.p, q = nd.q;int l = -1, r = info[rs].size();while(l + 1 < r) {int mid = (l + r) >> 1;(node[info[rs][mid]].r < p) ? (l = mid) : (r = mid);}for(int j = r; j < info[rs].size(); j++) {int id = info[rs][j];Node tmp = node[id];if((p > tmp.r) || (q < tmp.l)) break;int tl = max(tmp.l, p), tr = min(tmp.r, q);int pl, pr, nl, nr;if(!nd.rev) {pl = cl + tl - p;pr = cr - q + tr;}else {pl = cl + q - tr;pr = cr - tl + p;}if(!tmp.rev) {nl = tl + (tmp.p - tmp.l);nr = tr + (tmp.p - tmp.l);}else {nl = (tmp.p + tmp.r) - tr;nr = (tmp.p + tmp.r) - tl;}Node nw {pl, pr, nl, nr, min(nd.flag, 1) + min(tmp.flag, 1), nd.rev ^ tmp.rev};node[++c] = nw;nxt[i].push_back(c);nxt[id].push_back(c);info[o].push_back(c);}}vec[o] = info[o];sort(info[o].begin(), info[o].end(),[&](int x, int y) { return node[x].l < node[y].l; });sort(vec[o].begin(), vec[o].end(),[&](int x, int y) { return node[x].p < node[y].p; });}void Modify(int o, int l, int r, int x, int typ, int v) {if(l == r) {if(typ == 1) {node[++c] = Node {1, v, 1, v, 1, 0};info[o].push_back(c);if(v < n) {node[++c] = Node {v + 1, n, v + 1, n, 0, 0};info[o].push_back(c);}}else if(typ == 2) {node[++c] = Node {1, v, 1, v, 0, 1};info[o].push_back(c);if(v < n) {node[++c] = Node {v + 1, n, v + 1, n, 0, 0};info[o].push_back(c);}}else {node[++c] = Node {1, n, 1, n, 0, 0};info[o] = vector<int> {c};}vec[o] = info[o];return ;}int mid = (l + r) >> 1;if(mid >= x) Modify(ls, l, mid, x, typ, v);else Modify(rs, mid + 1, r, x, typ, v);Up(o);}vector<int> Erase(int o, int l, int r, int x) {if(l == r) {vector<int> v;for(int i : info[o]) {if(node[i].flag) {v.push_back(i);node[i].flag = 0;}}return v;}int mid = (l + r) >> 1;vector<int> vson, v;if(mid >= x) {vson = Erase(ls, l, mid, x);}else {vson = Erase(rs, mid + 1, r, x);}for(int i : vson) {for(int to : nxt[i]) {if(!--node[to].flag) v.push_back(to);}}return v;}int GetOld(int o, int v) {int p = -1, q = vec[o].size();while(p + 1 < q) {int mid = (p + q) >> 1;(node[vec[o][mid]].q < v) ? (p = mid) : (q = mid);}Node nd = node[vec[o][q]];if(!nd.rev) {return nd.l + v - nd.p;}else {return nd.l + nd.q - v;}}int GetNew(int o, int v) {int p = -1, q = info[o].size();while(p + 1 < q) {int mid = (p + q) >> 1;(node[info[o][mid]].r < v) ? (p = mid) : (q = mid);}Node nd = node[info[o][q]];if(!nd.rev) {return nd.p + v - nd.l;}else {return nd.p + nd.r - v;}}int GetId(int o, int l, int r, int x, int v, vector<Query> &qry) {if(vec[o].size() && (r <= x)) {int tp = GetOld(o, v);qry.push_back(Query {o, l, r, tp});return tp;}int mid = (l + r) >> 1;if(mid >= x) {return GetId(ls, l, mid, x, v, qry);}else {int p = GetId(rs, mid + 1, r, x, v, qry);return GetId(ls, l, mid, x, p, qry);}}int Find(int o, int l, int r, int v) {int p = -1, q = info[o].size();while(p + 1 < q) {int mid = (p + q) >> 1;(node[info[o][mid]].r < v) ? (p = mid) : (q = mid);}if(!node[info[o][q]].flag) return r + 1;if(l == r) return r;int mid = (l + r) >> 1;int lft = Find(ls, l, mid, v);return (lft > mid) ? Find(rs, mid + 1, r, GetNew(ls, v)) : lft;}
} sgt;int main() {// freopen("1.in", "r", stdin);// freopen("1.out", "w", stdout);ios::sync_with_stdio(0), cin.tie(0);cin >> n >> q;int lst = 0;for(int i = 1; i <= q; i++) {int a, b, c;cin >> a >> b >> c;b = (b + lst - 1) % ((a <= 2) ? n : q) + 1;c = (c + lst - 1) % n + 1;sgt.Modify(1, 1, q, i, a, b);if(a == 3) sgt.Erase(1, 1, q, b);vector<Query> vec;sgt.GetId(1, 1, q, i, c, vec);lst = 0;reverse(vec.begin(), vec.end());for(Query k : vec) {int tmp = sgt.Find(k.o, k.l, k.r, k.p);if(tmp <= k.r) {lst = tmp;break;}}cout << lst << "\n";}return 0;
}
http://www.jsqmd.com/news/71706/

相关文章:

  • 装饰模式
  • 2025年国内恒温恒湿试验箱生产厂家推荐/恒温恒湿试验箱十大国产品牌/行业十大排名 - 品牌推荐大师
  • 2025年12月危房检测,钢结构检测,外墙空鼓检测公司推荐:行业权威盘点与靠谱机构红榜​ - 品牌鉴赏师
  • BIM+GIS深度融合:高速公路数字化底座建设方案
  • 2025年12月精密铝压铸,铝合金压铸,铝压铸厂家推荐:行业权威盘点与品质红榜发布​ - 品牌鉴赏师
  • CH5xx 程序中获取代码大小
  • 2025年12月房屋沉降检测,房屋倾斜检测,房屋质量检测公司推荐:行业权威盘点与品质红榜发布​ - 品牌鉴赏师
  • 口碑好、实力强、高性价比的网站建设服务商推荐 - mypinpai
  • 上海全屋定制厂家推荐:靠谱之选打造理想家居 - myqiye
  • 2025年长三角包装印刷企业排名:上海万通卡牌印刷工艺怎样? - 工业品牌热点
  • 2025年河南正规叛逆学校排名:资质齐全的叛逆学校有哪些? - 工业推荐榜
  • 大一统视角理解扩散模型Understanding Diffusion Models: A Unified Perspective
  • 医用/低速/生物制药/血站/大容量/国产离心机/实验室离心机品牌选择指南及三大实力厂家深度解析 - 品牌推荐大师
  • 医用/低速/生物制药/血站/大容量/国产离心机/实验室离心机品牌选择指南及三大实力厂家深度解析 - 品牌推荐大师
  • C++学习笔记 03 枚举
  • 几种护眼色
  • TinyMCE + Vue 使用
  • 2025年北京合同审查工具服务排名:合同审查工具哪个好? - mypinpai
  • 2025年推荐厚片吸塑制品厂家TOP5:吸塑制品生产厂家解析 - 工业品牌热点
  • 2025年度回弹仪厂家实力排行榜TOP10,附联系电话,重型回弹仪/一体式数显回弹仪/红外分光光度计回弹仪供应厂家口碑推荐 - 品牌推荐师
  • 2025上海卡牌印刷公司TOP5权威推荐:专业测评指南,甄选 - 工业推荐榜
  • C++学习笔记02 static关键字
  • 深入解析:STM32外设学习-串口数据包笔记-(程序)
  • 告别臃肿:为什么 Drizzle ORM 是 TypeScript 后端的未来?
  • 保存文件带上时间蹉
  • 为什么我们需要使用react提供的ChildrenAPI而不是 JavaScript 的 map?
  • 医用/低速/生物制药/血站/大容量/微量高速/血库/自动/低温冷冻/国产离心机厂家排名 2025:实力厂家、优质品牌及选购技巧 - 品牌推荐大师
  • 暂时修复龙芯+深度 25Lazarus安装lazreport的lr_dialogdesign.lpk后Lazarus程序无法启动的Bug(完善的处理方法)
  • doker批量停用和删除容器命令
  • centos7创建swap linux创建swap 创建swap