POJ 3667 Hotel & HDU 2871 Memory Control 线段树区间合并

xiaoxiao2021-02-28  108

POJ 3667

参考

poj 3667 Hotel ——Titanium

题意

一条线段长度为 n ,初始未被覆盖。进行 两种操作 m 次: 1. 询问 最左边的 未被覆盖的 长度 D 的 区域的左端点,并覆盖这段区域; 2. 清除 [x,x+d1] 区域的覆盖。

思路

线段树上记录的信息还是老套路,左边连续的最大值,右边连续的最大值,一整段中的最大值;清除操作也是老套路, Lazy Tag 搞一搞。

关键就是询问操作怎么办。 可以认为与 hdu 2795 Billboard 转化 线段树 区间最大值 有异曲同工之处,那道题也是尽量向左找。

于是乎:先看 lson ,不满足的话就看中间拼起来的区域,再不满足再看 rson ,就解决了。

那么找到什么时候停呢? 一开始想着再记录一个信息,即这一段的最左边的端点,那么当其中的最大连续长度就等于查询长度的时候就可以不用继续往下找,而能直接返回这个纪录的值了。 后来发现不好维护,只好作罢= = 那么就一路向下找到叶子节点吧 _(:з」∠)_

Code

#include <cstdio> #include <iostream> #define lson (rt<<1) #define rson (rt<<1|1) #define maxn 50010 using namespace std; struct node { int l, r, mx, ml, mr, p, flag, len; }tr[maxn * 4]; void build(int rt, int l, int r) { tr[rt].l = l, tr[rt].r = r, tr[rt].len = tr[rt].ml = tr[rt].mr = tr[rt].mx = r-l+1; tr[rt].flag = -1; if (l == r) return; int mid = l + r >> 1; build(lson, l, mid); build(rson, mid+1, r); } void push_down(int rt) { if (tr[rt].flag != -1) { tr[lson].flag = tr[rson].flag = tr[rt].flag; tr[lson].ml = tr[lson].mr = tr[lson].mx = tr[lson].flag * tr[lson].len; tr[rson].ml = tr[rson].mr = tr[rson].mx = tr[rson].flag * tr[rson].len; tr[rt].flag = -1; } } void push_up(int rt) { tr[rt].ml = tr[lson].ml; if (tr[lson].ml == tr[lson].len) tr[rt].ml += tr[rson].ml; tr[rt].mr = tr[rson].mr; if (tr[rson].mr == tr[rson].len) tr[rt].mr += tr[lson].mr; tr[rt].mx = max(max(tr[lson].mx, tr[rson].mx), tr[lson].mr+tr[rson].ml); } int query(int rt, int len) { if (tr[rt].l == tr[rt].r && tr[rt].mx == len) return tr[rt].l; push_down(rt); if (tr[lson].mx >= len) return query(lson, len); else if (tr[lson].mr+tr[rson].ml >= len) return tr[lson].r-tr[lson].mr+1; else if (tr[rson].mx >= len) return query(rson, len); else return 0; } void modify(int rt, int l, int r, int x) { if (tr[rt].l == l && tr[rt].r == r) { tr[rt].ml = tr[rt].mr = tr[rt].mx = x * tr[rt].len; tr[rt].p = x ? tr[rt].l : 0; tr[rt].flag = x; return; } push_down(rt); int mid = tr[rt].l+tr[rt].r>>1; if (r <= mid) modify(lson, l, r, x); else if (l > mid) modify(rson, l, r, x); else { modify(lson, l, mid, x); modify(rson, mid+1, r, x); } push_up(rt); } int n, m; void work() { build(1, 1, n); while (m--) { int x, d, p, len; scanf("%d%d", &x, &d); if (x == 1) { int p = query(1, d); if (p) modify(1, p, d+p-1, 0); printf("%d\n", p); } else { scanf("%d", &len); modify(1, d, min(d+len-1, n), 1); } } } int main() { while (scanf("%d%d", &n, &m) != EOF) work(); return 0; }

HDU 2871

题意

一条线段长度为 n ,初始未被覆盖。进行 四种操作 m 次: 1.New D :询问 最左边的 未被覆盖的 长度 D 的 区域的左端点,并用一条线段覆盖这段区域; 2.Free x :清除覆盖 x 位置的线段; 3.Get x:打印第 x 条线段的左右端点; 4.Reset:清除所有线段。

思路

New 操作和上一题中差不多。 Free 的话一开始以为要写和 hdu 1540 Tunnel Warfare 线段树 / set 这道题差不多的,后来看了一些博客大家都是用的 vector 搞定的 Free Get 操作 0.0 (个人一直以为 vector 和数组效率差不多…就很害怕) 至于 Reset 就是一整段的 Free

Code

#include <bits/stdc++.h> #define maxn 50010 #define lson (rt<<1) #define rson (rt<<1|1) using namespace std; struct node { int l,r,ml,mr,mx,len,flag; }tr[maxn * 4]; vector<pair<int,int> > v; bool cmp(pair<int, int> u, pair<int, int> v) { return u.first < v.first; } void build(int rt, int l, int r) { tr[rt].l = l, tr[rt].r = r, tr[rt].len = r-l+1, tr[rt].flag = -1; tr[rt].ml = tr[rt].mr = tr[rt].mx = tr[rt].len; if (l == r) return; int mid = tr[rt].l + tr[rt].r >> 1; build(lson, l, mid); build(rson, mid+1, r); } void push_down(int rt) { if (tr[rt].flag != -1) { tr[lson].flag = tr[rson].flag = tr[rt].flag; tr[lson].ml = tr[lson].mr = tr[lson].mx = tr[rt].flag ? tr[lson].len : 0; tr[rson].ml = tr[rson].mr = tr[rson].mx = tr[rt].flag ? tr[rson].len : 0; tr[rt].flag = -1; } } void push_up(int rt) { tr[rt].ml = tr[lson].ml; if (tr[lson].ml == tr[lson].len) tr[rt].ml += tr[rson].ml; tr[rt].mr = tr[rson].mr; if (tr[rson].mr == tr[rson].len) tr[rt].mr += tr[lson].mr; tr[rt].mx = max(max(tr[lson].mx, tr[rson].mx), tr[lson].mr+tr[rson].ml); } int query(int rt, int len) { if (tr[rt].l == tr[rt].r && tr[rt].mx == len) return tr[rt].l; push_down(rt); if (tr[lson].mx >= len) return query(lson, len); else if (tr[lson].mr + tr[rson].ml >= len) return tr[lson].r-tr[lson].mr+1; else if (tr[rson].mx >= len) return query(rson, len); else return 0; } void modify(int rt, int l, int r, int x) { if (tr[rt].l == l && tr[rt].r == r) { tr[rt].ml = tr[rt].mr = tr[rt].mx = x ? tr[rt].len : 0; tr[rt].flag = x; return; } push_down(rt); int mid = tr[rt].l + tr[rt].r >> 1; if (r <= mid) modify(lson, l, r, x); else if (l > mid) modify(rson, l, r, x); else { modify(lson, l, mid, x); modify(rson, mid+1, r, x); } push_up(rt); } int m, n; void work() { build(1, 1, n); v.clear(); while (m--) { char s[10]; scanf("%s", s); char c = s[0]; if (c == 'R') { modify(1, 1, n, 1); v.clear(); printf("Reset Now\n"); continue; } int x; scanf("%d", &x); if (c == 'N') { int p = query(1, x); if (p) { modify(1, p, p+x-1, 0); pair<int, int> pr(p, p+x-1); auto it = lower_bound(v.begin(), v.end(), pr, cmp); v.insert(it, pr); printf("New at %d\n", p); } else printf("Reject New\n"); } else if (c == 'F') { pair<int, int> pr(x, x); auto it = upper_bound(v.begin(), v.end(), pr, cmp); if (it == v.begin()) printf("Reject Free\n"); else { --it; if (it->second >= x) { modify(1, it->first, it->second, 1); printf("Free from %d to %d\n", it->first, it->second); v.erase(it); } else printf("Reject Free\n"); } } else if (c == 'G') { if (x > v.size()) printf("Reject Get\n"); else printf("Get at %d\n", v[x-1].first); } } printf("\n"); } int main() { while (scanf("%d%d", &n, &m) != EOF) work(); return 0; }
转载请注明原文地址: https://www.6miu.com/read-53449.html

最新回复(0)