Address
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
r2≤l1 :子节点的标记变成
(
l
1
,
l
1
)
(l_1,l_1)
(l1,l1) 。
(2)
r
1
≤
l
2
r_1\le l_2
r1≤l2 :子节点的标记变成
(
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);
}