[BZOJ1513][POI2006]Tet-Tetris 3D
试题描述
Task: Tetris 3D "Tetris" 游戏的作者决定做一个新的游戏, 一个三维的版本, 在里面很多立方体落在平面板,一个立方体开始落下直到碰上一个以前落下的立方体或者落地即停止. 作者想改变一下游戏的目的使得它更大众化,在新游戏中你将知道落下的立方体信息以及位置,你的任务就是回答所有立方体落下后最高的方块的高度.所有的立方体在下落过程中都是垂直的并且不会旋转.平板左下角坐标为原点,并且平行于坐标轴.
输入
第一行给出三个整数 D, S and N ( 1<= N<= 20 000, 1<= D, S <=1 000), 分别表示平板的长和宽以及下落立方体的数目. 接下来N 行每行描述一个立方体. 每行包含5个整数: d, s, w, x and y (1<= d, 0 <=x, d + x<= D, 1 <=s, 0<= y, s + y<= S, 1<= w <=100 000), 分别表示立方体的长宽高以及落下的左下角坐标, 长和宽都是平行于平板坐标轴的,落下后立方体着地的四个角坐标分别为: (x, y), (x + d, y), (x, y + s) and (x + d, y + s).
输出
一个整数表示所有立方体落下后最高的方块的高度.
输入示例
7 5 4 4 3 2 0 0 3 3 1 3 0 7 1 2 0 3 2 3 3 2 2
输出示例
6
数据规模及约定
见“输入”
题解
二维线段树,其实可以理解成线段树套线段树。
外层线段树维护 x 坐标,内层维护 y 坐标;对于一个外层线段树节点 [l, r],它套着一个内层线段树,表示 x 坐标在 [l, r] 范围,y 坐标在 [1, S] 内的部分。所以当修改的时候(这里把子矩形用两个区间描述:[xl, xr] 和 [yl, yr] 分别表示 x 坐标的范围和 y 坐标的范围),在外层线段树找到 [xl, xr] 对应的 log 个区间,然后对于每个经过的区间都需要在它对应的内层线段树中做一个区间 [yl, yr] 取 max 的操作。外层的线段树因为套了另一个线段树所以得打静态标记,就是我们再开一个专门存标记的线段树,当询问的时候如果经过该节点则把该节点对应的存标记的线段树询问一下取个 max,然后再综合那 log 个区间对应的线段树的答案。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); } return x * f; } #define maxn 1010 #define maxnode 4000010 int ToT, maxv[maxnode], setv[maxnode], lc[maxnode], rc[maxnode]; void pushdown(int o, int l, int r) { if(!setv[o] || l == r){ setv[o] = 0; return ; } if(!lc[o]) lc[o] = ++ToT; setv[lc[o]] = max(setv[lc[o]], setv[o]); maxv[lc[o]] = max(maxv[lc[o]], setv[lc[o]]); if(!rc[o]) rc[o] = ++ToT; setv[rc[o]] = max(setv[rc[o]], setv[o]); maxv[rc[o]] = max(maxv[rc[o]], setv[rc[o]]); setv[o] = 0; return ; } void update(int& o, int l, int r, int ql, int qr, int val) { if(!o) o = ++ToT; pushdown(o, l, r); if(ql <= l && r <= qr) { setv[o] = max(setv[o], val); maxv[o] = max(maxv[o], setv[o]); return ; } int mid = l + r >> 1; if(ql <= mid) update(lc[o], l, mid, ql, qr, val); if(qr > mid) update(rc[o], mid + 1, r, ql, qr, val); maxv[o] = max(maxv[lc[o]], maxv[rc[o]]); return ; } int query(int o, int l, int r, int ql, int qr) { if(!o) return 0; pushdown(o, l, r); if(ql <= l && r <= qr) return maxv[o]; int mid = l + r >> 1, ans = 0; if(ql <= mid) ans = max(ans, query(lc[o], l, mid, ql, qr)); if(qr > mid) ans = max(ans, query(rc[o], mid + 1, r, ql, qr)); return ans; } int rt[maxn<<2], tag[maxn<<2], D, S; void modify(int o, int l, int r, int xl, int xr, int yl, int yr, int val) { update(rt[o], 1, S, yl, yr, val); if(xl <= l && r <= xr) return update(tag[o], 1, S, yl, yr, val); int mid = l + r >> 1, ls = o << 1, rs = ls | 1; if(xl <= mid) modify(ls, l, mid, xl, xr, yl, yr, val); if(xr > mid) modify(rs, mid + 1, r, xl, xr, yl, yr, val); return ; } int ask(int o, int l, int r, int xl, int xr, int yl, int yr) { int ans = query(tag[o], 1, S, yl, yr); if(xl <= l && r <= xr) return max(ans, query(rt[o], 1, S, yl, yr)); int mid = l + r >> 1, ls = o << 1, rs = ls | 1; if(xl <= mid) ans = max(ans, ask(ls, l, mid, xl, xr, yl, yr)); if(xr > mid) ans = max(ans, ask(rs, mid + 1, r, xl, xr, yl, yr)); return ans; } int main() { D = read(); S = read(); int N = read(); while(N--) { int d = read(), s = read(), w = read(), x = read(), y = read(); int tmp = ask(1, 1, D, x + 1, x + d, y + 1, y + s); // printf("%d %d %d %d: %d ", x + 1, x + d, y + 1, y + s, tmp); modify(1, 1, D, x + 1, x + d, y + 1, y + s, tmp + w); // printf("%d %d ", tmp + w, ask(1, 1, D, 1, D, 1, S)); } printf("%d ", ask(1, 1, D, 1, D, 1, S)); return 0; }
当然,我尝试过 kd 树。。。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); } return x * f; } #define maxn 1000010 #define oo 2000 bool Cur; struct Node { int x[2], mx[2], mn[2], setv, mxv, v; Node() { mx[0] = mx[1] = -oo; mn[0] = mn[1] = oo; setv = mxv = v = 0; } Node(int _x, int _y) { x[0] = _x; x[1] = _y; mx[0] = mx[1] = -oo; mn[0] = mn[1] = oo; setv = mxv = v = 0; } bool operator < (const Node& t) const { return x[Cur] != t.x[Cur] ? x[Cur] < t.x[Cur] : x[Cur^1] < t.x[Cur^1]; } } ns[maxn]; int ToT, lc[maxn], rc[maxn]; #define upd(t) ns[o].mn[t] = min(ns[o].x[t], min(ns[lc[o]].mn[t], ns[rc[o]].mn[t])), ns[o].mx[t] = max(ns[o].x[t], max(ns[lc[o]].mx[t], ns[rc[o]].mx[t])) void maintain(int o) { if(!o) return ; ns[0] = Node(); upd(0); upd(1); if(!ns[o].setv) ns[o].mxv = max(ns[o].v, max(ns[lc[o]].mxv, ns[rc[o]].mxv)); else ns[o].mxv = ns[o].v = ns[o].setv; return ; } void build(int& o, int l, int r, bool cur) { if(l > r){ o = 0; return ; } int mid = l + r >> 1; o = mid; Cur = cur; nth_element(ns + l, ns + mid, ns + r + 1); build(lc[o], l, mid - 1, cur ^ 1); build(rc[o], mid + 1, r, cur ^ 1); return maintain(o); } void pushdown(int o) { if(!ns[o].setv) return ; ns[lc[o]].setv = ns[lc[o]].mxv = ns[lc[o]].v = ns[rc[o]].setv = ns[rc[o]].mxv = ns[rc[o]].v = ns[o].setv; ns[0] = Node(); ns[o].setv = 0; return ; } Node cmd; #define all(t, o) (cmd.mn[t] <= ns[o].mn[t] && ns[o].mx[t] <= cmd.mx[t]) #define alln(t, o) (ns[o].mx[t] < cmd.mn[t] || cmd.mx[t] < ns[o].mn[t]) #define in(t, o) (cmd.mn[t] <= ns[o].x[t] && ns[o].x[t] <= cmd.mx[t]) void update(int o, int val) { if(!o) return ; pushdown(o); if(in(0, o) && in(1, o)) ns[o].v = val; if(all(0, lc[o]) && all(1, lc[o])) ns[lc[o]].setv = ns[lc[o]].mxv = ns[lc[o]].v = val; else if(!alln(0, lc[o]) && !alln(1, lc[o])) update(lc[o], val); if(all(0, rc[o]) && all(1, rc[o])) ns[rc[o]].setv = ns[rc[o]].mxv = ns[rc[o]].v = val; else if(!alln(0, rc[o]) && !alln(1, rc[o])) update(rc[o], val); return maintain(o); } int query(int o) { if(!o) return 0; pushdown(o); int ans = (in(0, o) && in(1, o)) ? ns[o].v : 0; if(all(0, lc[o]) && all(1, lc[o])) ans = max(ans, ns[lc[o]].mxv); else if(!alln(0, lc[o]) && !alln(1, lc[o])) ans = max(ans, query(lc[o])); if(all(0, rc[o]) && all(1, rc[o])) ans = max(ans, ns[rc[o]].mxv); else if(!alln(0, rc[o]) && !alln(1, rc[o])) ans = max(ans, query(rc[o])); return ans; } int main() { // freopen("data.in", "r", stdin); // freopen("data.out", "w", stdout); int D = read(), S = read(), N = read(); for(int i = 1; i <= D; i++) for(int j = 1; j <= S; j++) ns[++ToT] = Node(i, j); int rt, tot; build(rt, 1, ToT, 0); while(N--) { int d = read(), s = read(), w = read(), x = read(), y = read(); cmd.mn[0] = x + 1; cmd.mn[1] = y + 1; cmd.mx[0] = x + d; cmd.mx[1] = y + s; int tmp = query(rt); // printf("(%d, %d) (%d, %d) %d %d ", cmd.mn[0], cmd.mn[1], cmd.mx[0], cmd.mx[1], tmp, tmp + w); update(rt, tmp + w); } cmd.mn[0] = cmd.mn[1] = 1; cmd.mx[0] = D; cmd.mx[1] = S; printf("%d ", query(rt)); return 0; }
敢不敢交由你。。。