【UOJ 710】魔塔 OL(贪心)(四毛子分块)

魔塔 OL

题目链接:UOJ 710

题目大意

有一个三维的网格,点有权值 a,b,维护三个操作:
加入一个点,删除一个点, 把某一个 (1,x)(1,y)(1,y) 立方体里面的点拿出来,做一次操作的最小初始值。
操作是你按某个顺序删点,先把你的值减 a,再加上 b,要保证你的数不会小于 0 的最小初始值。

思路

首先考虑给出点集怎么做。
那你不难得到一个贪心:
首先选会让总值增加的 ab,那这其中我们肯定是要求从低到高,所以这些按 a 从小到大排。
那接着是 a>b,那减的总数已经确定,那我们肯定是尽可能的维持数大(在过程中),那你选某个数的时候,它的 a 是必减的,所以我们可以按 b 从大到小排。

那然后贪心看就行,接着看怎么快一点。
我们把所有点重新按这个贪心排序,然后我们考虑四毛子分块。


四毛子分块的想法是,我们选取一个很小的块,然后块内暴力处理出每一种情况的答案,然后跟之前的联系起来。


这里的话,我们就是 2B 算出里面每个点在或者不在,对块内做贪心的结果(要记录最后的和以及答案)
然后我们在求出每一维你 1x 包含了那些点,那三维的话就是三个点集的交。

但是会有一个小问题没有处理,就是它每个点有一个出现的区间(会删去)
那这个你拿左右两个指针扫,维护这个区间中的点集,然后再跟前面的取并即可。
然后就合并入之前的答案。

B 大概取 log 的位置,用 14

然后每次的时间就是 O(n2+nqlogn)

代码

#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; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/UOJ_710.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(69)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示