[BZOJ4364][IOI2014]wall磚牆(線段樹)
阿新 • • 發佈:2018-12-17
Address
Solution
線段樹。 每個節點維護標記: 表示所有小於 的數變成 ,大於 的數變成 。 初始標記為 。 對線段樹一個節點執行 Add 操作時,將該節點的 和 都對 取 。 執行 Remove 操作時,將該節點的 和 都對 取 。 接下來的重點就是下放標記了。(也就是說如何合併兩個標記) 如果線段樹父節點的標記 下傳到子節點,子節點原有的標記為 ,那麼分類討論一下: (1) :子節點的標記變成 。 (2) :子節點的標記變成 。 (3)否則子節點的標記變成 。 最後對線段樹進行 dfs ,到了葉子節點時的標記如果為 ,則該葉子節點對應下標的值為 。
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