POJ 3667
参考
题意
一条线段长度为
n
,初始未被覆盖。进行 两种操作
1. 询问 最左边的 未被覆盖的 长度
≥D
的 区域的左端点,并覆盖这段区域;
2. 清除
[x,x+d−1]
区域的覆盖。
思路
线段树上记录的信息还是老套路,左边连续的最大值,右边连续的最大值,一整段中的最大值;清除操作也是老套路, 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
,初始未被覆盖。进行 四种操作
1.New D
:询问 最左边的 未被覆盖的 长度
≥D
的 区域的左端点,并用一条线段覆盖这段区域;
2.Free x
:清除覆盖
x
位置的线段;
思路
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;
}