P8868 [NOIP2022] 比赛 题解
Description
小 N 和小 O 会在 2022 年 11 月参加一场盛大的程序设计大赛 NOIP!小 P 会作为裁判主持竞赛。小 N 和小 O 各自率领了一支
每场比赛前,考虑到路途距离,选手连续参加比赛等因素,小 P 会选择两个参数
NOIP 总共有
link。
Solution
考虑把询问离线下来然后对
设
那么区间
首先可以用单调栈维护对于每个
- 将区间的
更改为 。 - 将区间的
更改为 。 - 对于
里的所有 ,让 加 。
最后需要多次查询区间
考虑用线段树维护,容易发现每次操作之后
所以可以维护懒标记
考虑怎样合并两个懒标记
这里需要分类讨论
-
如果
和 都有赋值,那么只用更新 。 -
如果
有, 没有,那么可以用 的 和 更新 , 更新 ( 没有 没有是同理的)。 -
如果
和 都没有,那么只要将 的 更新 , 更新 , 更新 即可。
不要忘记
时间复杂度:
Code
#include <bits/stdc++.h> // #define int int64_t using u64 = uint64_t; const int kMaxN = 2.5e5 + 5; struct Node { u64 sumx, sumy, sumxy, sum; Node() {} Node(u64 _sumx, u64 _sumy, u64 _sumxy, u64 _sum) : sumx(_sumx), sumy(_sumy), sumxy(_sumxy), sum(_sum) {} friend Node operator +(Node n1, Node n2) { return {n1.sumx + n2.sumx, n1.sumy + n2.sumy, n1.sumxy + n2.sumxy, n1.sum + n2.sum}; } } t[kMaxN * 4]; struct Tag { u64 setx, sety, addx, addy, addxy, addc; // x 的赋值,y 的赋值,x 对 sum 的系数,y 对 sum 的系数,xy 对 sum 的系数,常数对 sum 的系数 Tag() {} Tag(u64 _setx, u64 _sety, u64 _addx, u64 _addy, u64 _addxy, u64 _addc) : setx(_setx), sety(_sety), addx(_addx), addy(_addy), addxy(_addxy), addc(_addc) {} friend Tag operator +(Tag t1, Tag t2) { // t1:前面的,t2:后面的 Tag ret = t1; if (t2.setx) ret.setx = t2.setx; if (t2.sety) ret.sety = t2.sety; if (t1.setx) { ret.addc += t1.setx * t2.addx; if (t1.sety) ret.addc += t1.sety * t2.addy + t1.setx * t1.sety * t2.addxy; else ret.addy += t2.addy + t1.setx * t2.addxy; } else { ret.addx += t2.addx; if (t1.sety) ret.addx += t1.sety * t2.addxy, ret.addc += t1.sety * t2.addy; else ret.addy += t2.addy, ret.addxy += t2.addxy; } ret.addc += t2.addc; return ret; } } tag[kMaxN * 4]; int n, q; int a[kMaxN], b[kMaxN], la[kMaxN], lb[kMaxN], stka[kMaxN], stkb[kMaxN]; u64 ans[kMaxN]; std::vector<std::pair<int, int>> vec[kMaxN]; Node merge(Node a, Tag t, int len) { Node ret = a; if (t.setx) ret.sumx = t.setx * len; if (t.sety) ret.sumy = t.sety * len; if (t.setx && t.sety) ret.sumxy = t.setx * t.sety * len; else if (t.setx) ret.sumxy = t.setx * a.sumy; else if (t.sety) ret.sumxy = t.sety * a.sumx; ret.sum += a.sumx * t.addx + a.sumy * t.addy + a.sumxy * t.addxy + t.addc * len; return ret; } struct SGT { Node t[kMaxN * 4]; Tag tag[kMaxN * 4]; void pushup(int x) { t[x] = t[x << 1] + t[x << 1 | 1]; } void addtag(int x, int l, int r, Tag tg) { t[x] = merge(t[x], tg, r - l + 1), tag[x] = tag[x] + tg; } void pushdown(int x, int l, int r) { if (!tag[x].setx && !tag[x].sety && !tag[x].addx && !tag[x].addy && !tag[x].addxy && !tag[x].addc) return; int mid = (l + r) >> 1; addtag(x << 1, l, mid, tag[x]), addtag(x << 1 | 1, mid + 1, r, tag[x]); tag[x] = {0, 0, 0, 0, 0, 0}; } void update(int x, int l, int r, int ql, int qr, Tag t) { if (l > qr || r < ql) { return; } else if (l >= ql && r <= qr) { return addtag(x, l, r, t); } pushdown(x, l, r); int mid = (l + r) >> 1; update(x << 1, l, mid, ql, qr, t), update(x << 1 | 1, mid + 1, r, ql, qr, t); pushup(x); } u64 query(int x, int l, int r, int ql, int qr) { if (l > qr || r < ql) { return 0; } else if (l >= ql && r <= qr) { return t[x].sum; } pushdown(x, l, r); int mid = (l + r) >> 1; return query(x << 1, l, mid, ql, qr) + query(x << 1 | 1, mid + 1, r, ql, qr); } } sgt; void dickdreamer() { int _case; std::cin >> _case >> n; for (int i = 1; i <= n; ++i) std::cin >> a[i]; for (int i = 1; i <= n; ++i) std::cin >> b[i]; std::cin >> q; for (int i = 1; i <= q; ++i) { int l, r; std::cin >> l >> r; vec[r].emplace_back(l, i); } int topa = 0, topb = 0; for (int i = 1; i <= n; ++i) { for (; topa && a[stka[topa]] < a[i]; --topa) {} for (; topb && b[stkb[topb]] < b[i]; --topb) {} la[i] = stka[topa], lb[i] = stkb[topb]; stka[++topa] = i, stkb[++topb] = i; sgt.update(1, 1, n, la[i] + 1, i, {a[i], 0, 0, 0, 0, 0}); sgt.update(1, 1, n, lb[i] + 1, i, {0, b[i], 0, 0, 0, 0}); sgt.update(1, 1, n, 1, i, {0, 0, 0, 0, 1, 0}); for (auto p : vec[i]) ans[p.second] = sgt.query(1, 1, n, p.first, i); } for (int i = 1; i <= q; ++i) std::cout << ans[i] << '\n'; } int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; // std::cin >> T; while (T--) dickdreamer(); // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n"; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步