Pretharp
2023-10-15 19:16:49
将一个不用维护线段树或者 ST 表之类数据结构的做法。
显然,将区间
接下来,我们只需要考虑在哪里使用这一次操作
此时,时间复杂度会爆炸,但是我们发现,若将
参考代码(cpp):
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e5 + 5, M = 22;
int n, m, q, ans, mn[N], a[N], sum1[N], sumt[N], sum0[N]; // mn[] 是对于每一个前缀归零的最小代价;sum1[] 是将需要修改为 1 的部分的前缀,sumt[] 和 sum0[] 则是后缀,详情见下。
struct Squ {
int a, b, c;
} s[N];
signed main() {
// freopen("reserve.in", "r", stdin);
// freopen("reserve.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> n;
for(int i = 1; i <= n; i ++) {
cin >> s[i].a;
}
for(int i = 1; i <= n; i ++) {
cin >> s[i].b;
}
for(int i = n; i >= 1; i --) {
sumt[i] = sumt[i + 1] + s[i].b;
}
for(int i = 1; i <= n; i ++) {
cin >> s[i].c;
}
for(int i = 1; i <= n; i ++) {
mn[i] = min(mn[i - 1] + s[i].b, s[i].a);
}
cin >> q;
while(q --) {
cin >> m, ans = 0x3f3f3f3f3f3f3f3f;
if(m == 0) { // 特殊情况。
cout << mn[n] << endl;
continue;
}
for(int i = 1; i <= m; i ++) { // 计算前缀。
cin >> a[i], sum1[i] = sum1[i - 1] + s[a[i]].c;
}
for(int i = m, cnt = 0; i >= 1; i --) { // 计算后缀。
cnt += s[a[i]].b;
sum0[i] = sumt[a[i]] - cnt;
}
for(int i = 1; i < m; i ++) {
ans = min(
ans,
mn[a[i + 1] - 1] + sum1[i] + sum0[i + 1]
);
}
ans = min({ans, mn[a[1] - 1] + sum0[1], mn[n] + sum1[m]}); // 值得一提的是,也有可能会在区间末尾(即第 n 个位置)使用归零。
cout << ans << endl;
}
return 0;
}