魔塔 OL
题目链接:UOJ 710
题目大意
有一个三维的网格,点有权值 a,b,维护三个操作:
加入一个点,删除一个点, 把某一个 (1,x)(1,y)(1,y) 立方体里面的点拿出来,做一次操作的最小初始值。
操作是你按某个顺序删点,先把你的值减 a,再加上 b,要保证你的数不会小于 0 的最小初始值。
思路
首先考虑给出点集怎么做。
那你不难得到一个贪心:
首先选会让总值增加的
a
⩽
b
a\leqslant b
a⩽b,那这其中我们肯定是要求从低到高,所以这些按
a
a
a 从小到大排。
那接着是
a
>
b
a>b
a>b,那减的总数已经确定,那我们肯定是尽可能的维持数大(在过程中),那你选某个数的时候,它的
a
a
a 是必减的,所以我们可以按
b
b
b 从大到小排。
那然后贪心看就行,接着看怎么快一点。
我们把所有点重新按这个贪心排序,然后我们考虑四毛子分块。
四毛子分块的想法是,我们选取一个很小的块,然后块内暴力处理出每一种情况的答案,然后跟之前的联系起来。
这里的话,我们就是
2
B
2^B
2B 算出里面每个点在或者不在,对块内做贪心的结果(要记录最后的和以及答案)
然后我们在求出每一维你
1
∼
x
1\sim x
1∼x 包含了那些点,那三维的话就是三个点集的交。
但是会有一个小问题没有处理,就是它每个点有一个出现的区间(会删去)
那这个你拿左右两个指针扫,维护这个区间中的点集,然后再跟前面的取并即可。
然后就合并入之前的答案。
B B B 大概取 log \log log 的位置,用 14 14 14。
然后每次的时间就是 O ( n 2 + n q log n ) O(\dfrac{n^2+nq}{\log n}) O(lognn2+nq)
代码
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 5e4 + 100;
const int V = 1e4 + 100;
const int B = 14;
struct Monster {
int l, r, x, y, z;
int a, b;
}a[N];
struct Quest {
int x, y, z, tim;
}qs[N];
int n, tot, q, lsts[1 << B], tim;
int xs[N], ys[N], zs[N];
ll sum[1 << B], maxn[1 << B], sums[N], ans[N];
vector <pair <int, int> > Ls, Rs;
bool cmp(Monster x, Monster y) {
if ((x.a <= x.b) ^ (y.a <= y.b)) return x.a <= x.b;
if (x.a <= x.b) return x.a < y.a;
else return x.b > y.b;
}
void work(int l, int r) {
int len = r - l + 1;
memset(xs, 0, sizeof(xs)); memset(ys, 0, sizeof(ys)); memset(zs, 0, sizeof(zs));
for (int i = l; i <= r; i++) {
xs[a[i].x] |= (1 << (i - l));
ys[a[i].y] |= (1 << (i - l));
zs[a[i].z] |= (1 << (i - l));
}
for (int i = 1; i < N; i++) xs[i] |= xs[i - 1], ys[i] |= ys[i - 1], zs[i] |= zs[i - 1];
for (int i = 1; i < (1 << len); i++) {
int id = lsts[i], fr = i ^ (1 << id); id += l;
maxn[i] = max(maxn[fr], sum[fr] + a[id].a);
sum[i] = sum[fr] + a[id].a - a[id].b;
}
Ls.clear(); Rs.clear();
for (int i = l; i <= r; i++) Ls.push_back(make_pair(a[i].l, i - l)), Rs.push_back(make_pair(a[i].r, i - l));
sort(Ls.begin(), Ls.end()); sort(Rs.begin(), Rs.end());
int lnum = 0, rnum = 0, suml = 0, sumr = 0;
for (int i = 1; i <= q; i++) {
while (lnum < len && Ls[lnum].first <= qs[i].tim) {
suml |= (1 << Ls[lnum].second); lnum++;
}
while (rnum < len && Rs[rnum].first <= qs[i].tim) {
sumr |= (1 << Rs[rnum].second); rnum++;
}
int S = xs[qs[i].x] & ys[qs[i].y] & zs[qs[i].z] & (suml ^ sumr);
ans[i] = max(ans[i], sums[i] + maxn[S]);
sums[i] += sum[S];
}
}
int main() {
for (int i = 1; i < (1 << B); i++) {
for (int j = 0; j < B; j++)
if ((i >> j) & 1) lsts[i] = j;
}
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
char op = getchar(); while (op != '+' && op != '-' && op != '?') op = getchar();
if (op == '+') {
int x, y, z, A, b; scanf("%d %d %d %d %d", &x, &y, &z, &A, &b);
a[++tot] = (Monster){++tim, n, x, y, z, A, b};
}
if (op == '-') {
int k; scanf("%d", &k);
a[k].r = ++tim;
}
if (op == '?') {
int x, y, z; scanf("%d %d %d", &x, &y, &z);
qs[++q] = (Quest){x, y, z, tim};
}
}
sort(a + 1, a + tot + 1, cmp);
for (int i = 1; i <= tot; i += B) {
int j = min(tot, i + B - 1);
work(i, j);
}
for (int i = 1; i <= q; i++) printf("%lld\n", ans[i]);
return 0;
}