[BZOJ4364][IOI2014]wall砖墙(线段树)

Address

洛谷P4560
BZOJ4364
UOJ#25

Solution

线段树。
每个节点维护标记: ( l , r ) (l,r) (l,r) 表示所有小于 l l l 的数变成 l l l ,大于 r r r 的数变成 r r r
初始标记为 ( 0 , 100000 ) (0,100000) (0,100000)
对线段树一个节点执行 Add x x x 操作时,将该节点的 l l l r r r 都对 x x x max ⁡ \max max
执行 Remove x x x 操作时,将该节点的 l l l r r r 都对 x x x min ⁡ \min min
接下来的重点就是下放标记了。(也就是说如何合并两个标记)
如果线段树父节点的标记 ( l 1 , r 1 ) (l_1,r_1) (l1,r1) 下传到子节点,子节点原有的标记为 ( l 2 , r 2 ) (l_2,r_2) (l2,r2) ,那么分类讨论一下:
(1) r 2 ≤ l 1 r_2\le l_1 r2l1 :子节点的标记变成 ( l 1 , l 1 ) (l_1,l_1) (l1,l1)
(2) r 1 ≤ l 2 r_1\le l_2 r1l2 :子节点的标记变成 ( r 1 , r 1 ) (r_1,r_1) (r1,r1)
(3)否则子节点的标记变成 ( max ⁡ ( l 1 , l 2 ) , min ⁡ ( r 1 , r 2 ) ) (\max(l_1,l_2),\min(r_1,r_2)) (max(l1,l2),min(r1,r2))
最后对线段树进行 dfs ,到了叶子节点时的标记如果为 ( l , r ) (l,r) (l,r) ,则该叶子节点对应下标的值为 l l l

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, mid, h, p2),
		pright(mid + 1, r, mid + 1, e, h, p3);
}

void output(int l, int r, int p, int ans[])
{
	if (l == r) return (void) (ans[l - 1] = le[p]);
	int mid = l + r >> 1;
	down(p, p2); down(p, p3);
	le[p] = 0; ri[p] = 100000;
	output(l, mid, p2, ans); output(mid + 1, r, p3, ans);
}

void buildWall(int n, int k, int op[], int left[], int right[],
	int height[], int finalHeight[])
{
	int i, t, l, r, h;
	For (i, 1, n << 2) le[i] = 0, ri[i] = 100000;
	For (i, 0, k - 1)
	{
		t = op[i]; l = left[i] + 1; r = right[i] + 1; h = height[i];
		if (t == 1) pleft(1, n, l, r, h, 1);
		else pright(1, n, l, r, h, 1);
	}
	output(1, n, 1, finalHeight);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值