BZOJ2704 旅游
BZOJ2402 陶陶的难题II

BZOJ1513 [POI2006]Tet-Tetris 3D

laekov posted @ 2015年3月07日 22:25 in 未分类 with tags bzoj ds , 826 阅读

这么水的题居然还要写题解。要不要说我写了半个下午+半个晚上。

 

丧心病狂想写一发zkw去抢速度rank。然后发现zkw怎么支持区间修改查询TT。课件根本没讲懂。而且max怎么区间加。

 

想了很久终于想出了来了。然后交上去发现常数巨大比普通线段树还要慢TT。到头来想想如果我直接写普通线段树说不定十多分钟就能过,而且代码量还会小一些。因为那个是可以直接通用的,但是这个比较麻烦。

 

其实写这个就题解就是想记录一下我yy出来的zkw区间修改区间查询的方法。

 

这道题是区间查询最大值+区间修改。如果是写一般的线段树,需要记录两个值a和v(至于为啥我用了这俩神奇的字母我也不知道),分别表示当前区间被完整覆盖的修改的最大值(又称lazy标记)和当前区间的最大值。然后所以zkw也要记这两个东西。

 

如果我们把zkw看作一棵树,那么每次修改和询问操作的时候都是对一些线段的a和v进行操作。(废话)

 

首先考虑修改。zkw经典的变为开区间取中间能处理a值的改变,但是不能处理v值的改变。因为v值改变的线段不一定会被当前区间包含。然后仔细考虑发现a值没有变但是v值变了的点只可能存在于两个端点到根的路径上。那就直接强行更新一发就好了啊。然后更新的区域就变成了一个有点像倒置漏斗的形状。

 

再考虑询问。a要覆盖当前区间,v要被当前区间覆盖。那不就是修改把a和v的做法反一下么。

 

然后好像也不是很麻烦的样子哈。

 

然后常数很大哈。

 

那还拿zkw做何用。

 

晕。

 

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>

using namespace std;

const int buf_len = 4567;
char buf[buf_len], *bufb(buf), *bufe(buf + 1);
#define readBuf() { \
	if (++ bufb == bufe) \
		bufe = (bufb = buf) + fread(buf, 1, sizeof(buf), stdin); \
}
#define readInt(_x_) { \
	register int _s_(0); \
	do { \
		readBuf(); \
	} while (!isdigit(*bufb)); \
	do { \
		_s_ = _s_ * 10 + *bufb - 48; \
		readBuf(); \
	} while (isdigit(*bufb)); \
	_x_ = _s_; \
}

const int maxn = 2049;

int q, n, m, bn, bm;

inline void upMax(int& a, int b) {
	if (a < b)
		a = b;
}
#define upMax_d(_a_,_b_) { \
	if (_a_ < _b_) \
		_a_ = _b_; \
}

struct zkw_tree_y {
	int v[maxn], a[maxn];
	zkw_tree_y() {
		memset(v, 0, sizeof(v));
		memset(a, 0, sizeof(a));
	}
	int qry(int lo, int ro) {
		int s(0), l, r;
		for (l = lo + bm; l; l >>= 1)
			upMax_d(s, a[l]);
		for (r = ro + bm; r; r >>= 1)
			upMax_d(s, a[r]);
		for (l = lo + bm - 1, r = ro + bm + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
			if (!(l & 1))
				upMax_d(s, v[l ^ 1]);
			if (r & 1)
				upMax_d(s, v[r ^ 1]);
		}
		return s;
	}
	void chg(int lo, int ro, int h) {
		int l, r;
		for (l = lo + bm; l; l >>= 1)
			upMax_d(v[l], h);
		for (r = ro + bm; r; r >>= 1)
			upMax_d(v[r], h);
		for (l = lo + bm - 1, r += ro + bm + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
			if (!(l & 1)) {
				upMax_d(a[l ^ 1], h);
				upMax_d(v[l ^ 1], h);
			}
			if (r & 1) {
				upMax_d(a[r ^ 1], h);
				upMax_d(v[r ^ 1], h);
			}
		}
	}
};

zkw_tree_y v[maxn], a[maxn];

int zkwQryX(int lo, int ro, int yl, int yr) {
	int s(0), l, r;
	for (l = lo + bn; l; l >>= 1)
		upMax(s, a[l]. qry(yl, yr));
	for (r = ro + bn; r; r >>= 1)
		upMax(s, a[r]. qry(yl, yr));
	for (l = lo + bn - 1, r = ro + bn + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (!(l & 1))
			upMax(s, v[l ^ 1]. qry(yl, yr));
		if (r & 1)
			upMax(s, v[r ^ 1]. qry(yl, yr));
	}
	return s;
}
void zkwChgX(int lo, int ro, int yl, int yr, int h) {
	int l, r;
	for (l = lo + bn; l; l >>= 1)
		v[l]. chg(yl, yr, h);
	for (r = ro + bn; r; r >>= 1)
		v[r]. chg(yl, yr, h);
	for (l = lo + bn - 1, r = ro + bn + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (!(l & 1)) {
			a[l ^ 1]. chg(yl, yr, h);
			v[l ^ 1]. chg(yl, yr, h);
		}
		if (r & 1) {
			a[r ^ 1]. chg(yl, yr, h);
			v[r ^ 1]. chg(yl, yr, h);
		}
	}
}

int main() {
#ifndef ONLINE_JUDGE
//	freopen("in.txt", "r", stdin);
#endif

	readInt(n);
	readInt(m);
	readInt(q);
	memset(a, 0, sizeof(a));
	memset(v, 0, sizeof(v));
	for (bn = 1; bn < n + 2; bn <<= 1);
	for (bm = 1; bm < m + 2; bm <<= 1);
	while (q --) {
		int x, y, p, q, h;
		readInt(p);
		readInt(q);
		readInt(h);
		readInt(x);
		readInt(y);
		p += x ++, q += y ++;
		h += zkwQryX(x, p, y, q);
		zkwChgX(x, p, y, q, h);
	}
	printf("%d\n", zkwQryX(1, n, 1, m));
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter