Register_int
2024-11-18 22:39:07
这也太牛了。
只考虑查询的话是个朴素的 01 背包问题,但是前面有各种奇怪的修改,貌似不好解决。
首先将“新开连锁店”的操作解决。这里可以使用 可持久化并查集 中的技巧,将所有版本建成一棵树,在树上跑搜即可。这样就只需支持撤销。
题目剩下两种操作又是从两种方向修改,要支持头尾插入撤销。我们知道 01 背包是容易支持撤销的,所以朴素的想法是维护两个栈,一个负责头一个负责尾,分别维护自身的 01 背包,查询时可以将两个背包的这一单点
那一个栈空了怎么办呢?参考 C++ 中的 deque 是怎么维护的。它的底层是两个 vector,一个被删空时会将满的那边分一半过去,复杂度是均摊
总时间复杂度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 3e4 + 10;
const int MAXM = 2e3 + 10;
vector<pair<int, int>> G[MAXN], q[MAXN]; vector<int> af, ag;
int rt[MAXN], p[MAXN], t[MAXN], tf, tg, tot, cnt, tp, tq;
int n, f[MAXN][MAXM], g[MAXN][MAXM], ans[MAXN];
inline
void addf(int x) {
af.emplace_back(x), tf++, memcpy(f[tf], f[tf - 1], sizeof f[tf - 1]);
for (int i = 2e3; i >= p[x]; i--) f[tf][i] = max(f[tf - 1][i], f[tf - 1][i - p[x]] + t[x]);
for (int i = 1; i <= 2e3; i++) f[tf][i] = max(f[tf][i], f[tf][i - 1]);
}
inline
void addg(int x) {
ag.emplace_back(x), tg++, memcpy(g[tg], g[tg - 1], sizeof g[tg - 1]);
for (int i = 2e3; i >= p[x]; i--) g[tg][i] = max(g[tg][i], g[tg - 1][i - p[x]] + t[x]);
for (int i = 1; i <= 2e3; i++) g[tg][i] = max(g[tg][i], g[tg][i - 1]);
}
inline
void rebuild(bool t) {
vector<int> tmp;
for (int x : af) tmp.emplace_back(x);
reverse(tmp.begin(), tmp.end());
for (int x : ag) tmp.emplace_back(x);
int x = (tmp.size() + t) >> 1; tf = tg = 0, af.clear(), ag.clear();
for (int i = x - 1; ~i; i--) addf(tmp[i]);
for (int i = x; i < tmp.size(); i++) addg(tmp[i]);
}
inline
int delf() {
if (af.empty()) rebuild(1);
int x = af.back(); return af.pop_back(), tf--, x;
}
inline
int delg() {
if (ag.empty()) rebuild(0);
int x = ag.back(); return ag.pop_back(), tg--, x;
}
inline
int ask(int x) {
int ans = 0;
for (int i = 0; i <= x; i++) ans = max(ans, f[tf][i] + g[tg][x - i]);
return ans;
}
void dfs(int u) {
for (pair<int, int> x : q[u]) ans[x.second] = ask(x.first);
for (pair<int, int> x : G[u]) {
int v = x.first, w = x.second;
if (w) addg(w), dfs(v), delg();
else w = delf(), dfs(v), addf(w);
}
}
int main() {
scanf("%d", &n), rt[1] = tot = cnt = 1;
for (int i = 1, op, x, y; i <= n; i++) {
scanf("%d%d", &op, &x);
if (op == 1) rt[++cnt] = rt[x];
if (op == 2) {
tp++, scanf("%d%d", &p[tp], &t[tp]);
G[rt[x]].emplace_back(++tot, tp), rt[x] = tot;
}
if (op == 3) G[rt[x]].emplace_back(++tot, 0), rt[x] = tot;
if (op == 4) scanf("%d", &y), q[rt[x]].emplace_back(y, ++tq);
}
dfs(1);
for (int i = 1; i <= tq; i++) printf("%d\n", ans[i]);
}