abc343F 区间第2大的出现次数
给定数组a[n],有Q组操作,格式为:
- 1 p x,将a[p]修改为x;
- 2 l r,查询区间[l,r]内第2大元素的出现次数。
1<=n,q<=2e5; 1<=a[i]<=1e9
用线段树维护各个区间的最大及次大元素的出现次数,合并时最多只保留两条记录。
#include <bits/stdc++.h> using i64 = long long; template<class Info> struct SegmentTree { int n; std::vector<Info> info; SegmentTree():n(0) {} SegmentTree(int _n, Info v = Info()) { init(_n, v); } void init(int _n, Info v = Info()) { init(std::vector<Info>(_n, v)); } template<class T> SegmentTree(std::vector<T> v) { init(v); } template<class T> void init(std::vector<T> v) { n = v.size(); info.assign(4 << std::__lg(n), Info()); std::function<void(int,int,int)> build = [&](int x, int l, int r) { if (l + 1 == r) { info[x] = v[l]; return; } int m = (l + r) / 2; build(2*x+1, l, m); build(2*x+2, m, r); pushup(x); }; build(0, 0, n); } void pushup(int x) { info[x] = info[2*x+1] + info[2*x+2]; } void modify(int x, int l, int r, int p, const Info &v) { if (l + 1 == r) { info[x] = v; return; } int m = (l + r) / 2; if (p < m) { modify(2*x+1, l, m, p, v); } else { modify(2*x+2, m, r, p, v); } pushup(x); } void modify(int p, const Info &v) { modify(0, 0, n, p, v); } Info rangeQuery(int x, int l, int r, int L, int R) { if (R <= l || r <= L) { return Info(); } if (L <= l && r <= R) { return info[x]; } int m = (l + r) / 2; return rangeQuery(2*x+1, l, m, L, R) + rangeQuery(2*x+2, m, r, L, R); } Info rangeQuery(int L, int R) { return rangeQuery(0, 0, n, L, R); } template<class F> int findFirst(int x, int l, int r, int L, int R, F pred) { if (R <= l || r <= L || !pred(info[x])) { return -1; } if (l + 1 == r) { return l; } int m = (l + r) / 2; int res = findFirst(2*x+1, l, m, L, R, pred); if (res == -1) { res = findFirst(2*x+2, m, r, L, R, pred); } return res; } template<class F> int findFirst(int L, int R, F pred) { return findFirst(0, 0, n, L, R, pred); } template<class F> int findLast(int x, int l, int r, int L, int R, F pred) { if (R <= l || r <= L || !pred(info[x])) { return -1; } if (l + 1 == r) { return l; } int m = (l + r) / 2; int res = findLast(2*x+2, m, r, L, R, pred); if (res == -1) { res = findLast(2*x+1, l, m, L, R, pred); } return res; } template<class F> int findLast(int L, int R, F pred) { return findLast(0, 0, n, L, R, pred); } }; struct Info { int max1, cnt1, max2, cnt2; Info(int v=0):max1(v),cnt1(1),max2(0),cnt2(0) {} friend Info operator+(const Info &a, const Info &b) { Info ans; std::map<int,int> mp; if (a.max1 > 0) mp[a.max1] += a.cnt1; if (a.max2 > 0) mp[a.max2] += a.cnt2; if (b.max1 > 0) mp[b.max1] += b.cnt1; if (b.max2 > 0) mp[b.max2] += b.cnt2; auto it = mp.rbegin(); if (it != mp.rend()) { ans.max1 = it->first; ans.cnt1 = it->second; ++it; if (it != mp.rend()) { ans.max2 = it->first; ans.cnt2 = it->second; } } return ans; } }; void solve() { int n, q; std::cin >> n >> q; std::vector<i64> a(n); for (int i = 0; i < n; i++) { std::cin >> a[i]; } SegmentTree<Info> seg(a); for (int i = 0; i < q; i++) { int op, x, y; std::cin >> op >> x >> y; if (op == 1) { seg.modify(x-1, Info(y)); } else if (op == 2) { std::cout << seg.rangeQuery(x-1, y).cnt2 << "\n"; } } } int main() { std::cin.tie(0)->sync_with_stdio(0); int t = 1; while (t--) solve(); return 0; }
标签:
线段树
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现