魔塔 OL

题目链接:UOJ 710

题目大意

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

思路

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

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


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


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

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

\(B\) 大概取 \(\log\) 的位置,用 \(14\)

然后每次的时间就是 \(O(\dfrac{n^2+nq}{\log n})\)

代码

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

原文地址:http://www.cnblogs.com/Sakura-TJH/p/UOJ_710.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性