[jzoj5073 GDOI2017第二轮模拟] 影魔
Solution
把所有询问离线
用单调栈分别做两次,求出对于排列数组的单个元素从自己开始到左边和到右边的最远的端点
为了处理贡献对应询问的区间建出一颗线段树
按左端点排序询问,枚举区间内的元素,设当前元素为最大值,那么,从它到区间端点(端点作为最大值)的这个区间的都可以打上p2贡献的标记
设当前元素为次小值,那么,对区间端点打上p1-p2-p2的标记(作为次小有两次重复)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | #include <stdio.h> #include <string.h> #include <algorithm> #define _L long long #define _RG register int #define lson s, mid, k << 1 #define rson mid + 1, t, k << 1 | 1 const int N = 200010; int n, m, p1, p2, a[N], l[N], r[N], steck[N], sec, nex[N], tim; _L tag[N << 2], sum[N << 2], ans[N]; struct Q { int l, r, id; }que[N]; inline void downt(_RG s, _RG t, _RG k) { sum[k] += tag[k] * (_L)(t - s + 1); if (s ^ t) tag[k << 1] += tag[k], tag[k << 1 | 1] += tag[k]; tag[k] = 0; } void updat(_RG s, _RG t, _RG k, _RG x, _RG y, _RG z) { _RG mid = s + t >> 1; downt(s, t, k); if (s ^ t) downt(s, mid, k << 1), downt(mid + 1, t, k << 1 | 1); if (s == x && t == y) { tag[k] += z; downt(s, t, k); return ; } if (y <= mid) updat(lson, x, y, z); else if (x > mid) updat(rson, x, y, z); else updat(lson, x, mid, z), updat(rson, mid + 1, y, z); sum[k] = sum[k << 1] + sum[k << 1 | 1]; } _L query(_RG s, _RG t, _RG k, _RG x, _RG y) { _RG mid = s + t >> 1; downt(s, t, k); if (s ^ t) downt(s, mid, k << 1), downt(mid + 1, t, k << 1 | 1); if (s == x && t == y) return sum[k]; if (y <= mid) return query(lson, x, y); if (x > mid) return query(rson, x, y); return query(lson, x, mid) + query(rson, mid + 1, y); } void solve() { for (_RG i = 1; i <= m; ++i) que[i] = (Q) {l[i], r[i], i}; std::sort(que + 1, que + 1 + m, []( const Q &u, const Q &v) { return u.l > v.l;}); steck[sec = 1] = n + 1; a[n + 1] = 1e9; for (_RG i = n; i; --i) { while (sec && a[steck[sec]] < a[i]) --sec; nex[i] = steck[sec]; steck[++sec] = i; } tim = 1; for (_RG i = n; i; --i) { updat(1, n + 1, 1, i + 1, nex[i], p2); updat(1, n + 1, 1, nex[i], nex[i], p1 - p2 - p2); while (tim <= m && que[tim].l == i) { ans[que[tim].id] += query(1, n + 1, 1, i, que[tim].r); ++tim; } if (tim > m) break ; } } int main() { scanf ( "%d%d%d%d" , &n, &m, &p1, &p2); for (_RG i = 1; i <= n; ++i) scanf ( "%d" , a + i); for (_RG i = 1; i <= m; ++i) scanf ( "%d%d" , l + i, r + i); solve(); memset (sum, 0LL, sizeof sum), memset (tag, 0LL, sizeof tag); for (_RG i = 1; i <= n / 2; ++i) std::swap(a[i], a[n - i + 1]); for (_RG i = 1; i <= m; ++i) l[i] = n - l[i] + 1, r[i] = n - r[i] + 1, std::swap(l[i], r[i]); solve(); for (_RG i = 1; i <= m; ++i) printf ( "%lld\n" , ans[i]); return 0; } |
枚举当前数为次小值,则可以直接为区间加上贡献,用线段树覆盖,
分类:
数据结构---单调栈
, 数据结构---线段树
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)