维护集合最值和集合全体加
title: 维护集合最值和集合全体加
categories:
- ICPC
tags:
- null
abbrlink: e5b5491f
date: 2024-02-10 00:00:00
维护集合最值和集合全体加
你有一个可重集合初始有n个数,有4种操作,$5e5次操作$
- 向集合中加入一个数
- 删除集合中一个数
- 集合中所有数加x
- 查询集合最大值
进一步考虑另一个可以使用这个模型的问题。一个vector,动态在尾部增加数,删除数,边操作边求后缀和最小值
#include <bits/stdc++.h>
#ifdef LOCAL
#include "debug.h"
#else
#define deb(...)
#endif
using namespace std;
#define ll long long
// #define int long long
#define ull unsigned long long
#define pii pair<int, int>
#define db double
#define baoliu(x, y) cout << fixed << setprecision(y) << x
#define endl "\n"
#define alls(x) (x).begin(), (x).end()
#define fs first
#define sec second
#define bug(x) cerr << #x << " = " << x << endl
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-8;
const double PI = acos(-1.0);
void solve() {
int n;
cin >> n;
vector<int> a(n + 1);
vector<int> suf(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = n; i >= 1; i--) {
if (i == n)
suf[i] = a[i];
else
suf[i] = suf[i + 1] + a[i];
}
multiset<int> st;
for (int i = 1; i <= n; i++) st.insert(suf[i]);
int offset = 0;
int sufsum = suf[1];
// 集合所有数加上x
auto update = [&](int x) {
offset += x;
};
// 1-加入一个数到集合
auto add = [&](int x) {
st.insert(x - offset);
};
// 2-删除集合里的数,保证存在
auto del = [&](int x) {
int cur = x - offset;
assert(st.find(cur) != st.end());
st.erase(st.find(cur));
};
// 3-查询后缀和最大值
auto query = [&] {
return *prev(st.end()) + offset;
};
int m;
cin >> m;
for (int i = 1; i <= m; i++) {
int op;
cin >> op;
if (op == 1) {
int x;
cin >> x;
sufsum += x;
a.push_back(x);
update(x);
add(sufsum);
} else if (op == 2) {
int x = a.back();
a.pop_back();
del(sufsum);
sufsum -= x;
update(-x);
} else
cout << query() << endl;
}
}
signed main() {
cin.tie(0);
ios::sync_with_stdio(false);
#ifdef LOCAL
double starttime = clock();
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif
int t = 1;
// cin >> t;
while (t--) solve();
#ifdef LOCAL
double endtime = clock();
cerr << "Time Used: " << (double)(endtime - starttime) / CLOCKS_PER_SEC * 1000 << " ms" << endl;
#endif
return 0;
}
怎么转化的?
假设初始有n个元素 我就把n个后缀和存进集合里。需要维护如下操作:
集合删去一个数,并且集合中每个数减去这个数
集合加入一个数,并且集合中每个数加上这个数
求集合最小值
开一个vector按照题意模拟就可以知道每次最后一个数是谁,维护一个sufsum就可以知道当前后缀和是多少,用multiset就可以知道集合最小值。
- 唯一要解决的问题就是集合一起加一个数怎么维护
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 爱飞鱼的blog!