1. 程式人生 > >[BZOJ4364][IOI2014]wall磚牆(線段樹)

[BZOJ4364][IOI2014]wall磚牆(線段樹)

Address

Solution

線段樹。 每個節點維護標記: (l,r)(l,r) 表示所有小於 ll 的數變成 ll ,大於 rr 的數變成 rr 。 初始標記為 (0,100000)(0,100000) 。 對線段樹一個節點執行 Add xx 操作時,將該節點的 llrr 都對 xxmax\max 。 執行 Remove xx 操作時,將該節點的 llrr 都對 xxmin\min 。 接下來的重點就是下放標記了。(也就是說如何合併兩個標記) 如果線段樹父節點的標記 (l1,r1)(l_1,r_1) 下傳到子節點,子節點原有的標記為 (

l2,r2)(l_2,r_2) ,那麼分類討論一下: (1) r2l1r_2\le l_1 :子節點的標記變成 (l1,l1)(l_1,l_1) 。 (2) r1l2r_1\le l_2 :子節點的標記變成 (r1,r1)(r_1,r_1) 。 (3)否則子節點的標記變成 (max(l1,l2),min(r1,r2))(\max(l_1,l_2),\min(r_1,r_2)) 。 最後對線段樹進行 dfs ,到了葉子節點時的標記如果為 (l,r)(l,r)
,則該葉子節點對應下標的值為 ll

Code

完整程式:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define p2 p << 1
#define p3 p << 1 | 1

inline int read()
{
	int res = 0; bool
bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } template <class T> T Min(T a, T b) {return a < b ? a : b;} template <class T> T Max(T a, T b) {return a > b ? a : b;} const int N = 8e6 + 5; int n, m, le[N], ri[N]; void down(int p, int to) { if (ri[to] <= le[p]) le[to] = ri[to] = le[p]; else if (ri[p] <= le[to]) le[to] = ri[to] = ri[p]; else le[to] = Max(le[to], le[p]), ri[to] = Min(ri[to], ri[p]); } void pleft(int l, int r, int s, int e, int h, int p) { if (l == s && r == e) { if (ri[p] <= h) le[p] = ri[p] = h; else le[p] = Max(le[p], h); return; } int mid = l + r >> 1; down(p, p2); down(p, p3); le[p] = 0; ri[p] = 100000; if (e <= mid) pleft(l, mid, s, e, h, p2); else if (s >= mid + 1) pleft(mid + 1, r, s, e, h, p3); else pleft(l, mid, s, mid, h, p2), pleft(mid + 1, r, mid + 1, e, h, p3); } void pright(int l, int r, int s, int e, int h, int p) { if (l == s && r == e) { if (h <= le[p]) le[p] = ri[p] = h; else ri[p] = Min(ri[p], h); return; } int mid = l + r >> 1; down(p, p2); down(p, p3); le[p] = 0; ri[p] = 100000; if (e <= mid) pright(l, mid, s, e, h, p2); else if (s >= mid + 1) pright(mid + 1, r, s, e, h, p3); else pright(l, mid, s, mid, h, p2), pright(mid + 1, r, mid + 1, e, h, p3); } void output(int l, int r, int p) { if (l == r) return (void) (printf("%d\n", le[p])); int mid = l + r >> 1; down(p, p2); down(p, p3); le[p] = 0; ri[p] = 100000; output(l, mid, p2); output(mid + 1, r, p3); } int main() { int i, t, l, r, h; n = read(); m = read(); For (i, 1, n << 2) le[i] = 0, ri[i] = 100000; while (m--) { t = read(); l = read() + 1; r = read() + 1; h = read(); if (t == 1) pleft(1, n, l, r, h, 1); else pright(1, n, l, r, h, 1); } output(1, n, 1); return 0; }

互動:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include "wall.h"
#define For(i, a, b) for (i = a; i <= b; i++)
#define p2 p << 1
#define p3 p << 1 | 1

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? -res : res;
}

template <class T>
T Min(T a, T b) {return a < b ? a : b;}

template <class T>
T Max(T a, T b) {return a > b ? a : b;}

const int N = 8e6 + 5;

int le[N], ri[N];

void down(int p, int to)
{
	if (ri[to] <= le[p]) le[to] = ri[to] = le[p];
	else if (ri[p] <= le[to]) le[to] = ri[to] = ri[p];
	else le[to] = Max(le[to], le[p]),
		ri[to] = Min(ri[to], ri[p]);
}

void pleft(int l, int r, int s, int e, int h, int p)
{
	if (l == s && r == e)
	{
		if (ri[p] <= h) le[p] = ri[p] = h;
		else le[p] = Max(le[p], h);
		return;
	}
	int mid = l + r >> 1;
	down(p, p2); down(p, p3);
	le[p] = 0; ri[p] = 100000;
	if (e <= mid) pleft(l, mid, s, e, h, p2);
	else if (s >= mid + 1) pleft(mid + 1, r, s, e, h, p3);
	else pleft(l, mid, s, mid, h, p2),
		pleft(mid + 1, r, mid + 1, e, h, p3);
}

void pright(int l, int r, int s, int e, int h, int p)
{
	if (l == s && r == e)
	{
		if (h <= le[p]) le[p] = ri[p] = h;
		else ri[p] = Min(ri[p], h);
		return;
	}
	int mid = l + r >> 1;
	down(p, p2); down(p, p3);
	le[p] = 0; ri[p] = 100000;
	if (e <= mid) pright(l, mid, s, e, h, p2);
	else if (s >= mid + 1) pright(mid + 1, r, s, e, h, p3);
	else pright(l, mid, s