USACO 2008 February Gold / 洛谷 P2894 | Hotel

题目链接:

线段树好题。

线段树的节点中存储这几个东西:

  • maxmax,代表区间最大子段和
  • frontfront,代表区间最大前缀和
  • backback,代表区间最大后缀和
  • sumsum,代表区间和
  • lzylzy,代表懒标记,只可能有两种状态:退房与开房

初始化时,将所有节点设置为 11,代表是空房。

操作 2 很简单,将 xxx+y1x+y-1 全部标记为 11 即可。

操作 1 稍微有一些难度,直接放上结论。首先在整段区间上查询最大子段和,如果 xmaxx \le max,代表有超过 xx 个连续的空房,则开始寻找目标房间。

在一个段内寻找空房的最左端时,将整个段分成两部分,分类讨论。

  • 左段的最大子段和满足 xmaxx \le max,递归查询左段。
  • 左段的最大后缀和与右段的最大前缀和的和满足 x(back+front)x \le (back+front),连续空房刚好横跨左右段,直接返回。
  • 右段的最大子段和满足 xmaxx \le max,递归查询右段。

查询后区间赋值为 00,代表有人。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/******************************
@GavinCQTD / 2024-12-10 15:55:25
"P2894 [USACO08FEB] Hotel G" From Luogu
# https://www.luogu.com.cn/problem/P2894
1000 ms / 128 MB
******************************/
/* We all make choices, but in the end our choices make us. */

// #pragma GCC optimize(1,2,3,"Ofast","inline")

// #define NDEBUG

#include <iostream>
#include <algorithm>
#include <cassert>
#include <cstring>
#include <iomanip>
#include <cstdio>
#include <cmath>
using namespace std;
inline void pass(){return;}
inline void hold(){while(1);}
#define endl "\n"
#define mp(a,b) make_pair(a,b)
#define ct(a) while(!a.empty()) a.pop()
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
#define cdb cerr<<"Debug: "
#define cwn cerr<<"Warn: "
#define debug(x) cerr<<"In Line "<<__LINE__<<": "<<#x<<" = "<<x<<"\n"
#define sp(a) fixed<<setprecision(a)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define ll long long
#define ull unsigned long long
#define ld long double
// #define int ll
// #define _debug

int _t,n,m;
struct seg{
int max=-100000,front,back,sum,lzy;
}tree[2000005];

inline void pushup(int u){
tree[u].front = max(tree[u*2].front, tree[u*2].sum+tree[u*2+1].front);
tree[u].back = max(tree[u*2+1].back, tree[u*2+1].sum+tree[u*2].back);
tree[u].sum = tree[u*2].sum+tree[u*2+1].sum;
tree[u].max = max(tree[u*2].max, max(tree[u*2+1].max, tree[u*2].back+tree[u*2+1].front));
}
inline void init(int u,int val){
tree[u].max = val;
tree[u].front = val;
tree[u].back = val;
tree[u].sum = val;
}

void build(int u,int l,int r){
if(l==r){
init(u, 1);
return;
}
int mid=(l+r)>>1;
build(u*2,l,mid);
build(u*2+1,mid+1,r);
pushup(u);
}

inline bool inrange(int l,int r,int ql,int qr){return (ql<=l)&&(r<=qr);}
inline bool outofrange(int l,int r,int ql,int qr){return (l>qr)||(r<ql);}

inline seg get(seg l,seg r){
seg res;
res.front = max(l.front, l.sum+r.front);
res.back = max(r.back, r.sum+l.back);
res.sum = l.sum+r.sum;
res.max = max(l.max, max(r.max, l.back+r.front));
return res;
}

inline void maketag(int u,int ul,int ur,int uk){
if(uk==1){
tree[u].lzy = 1;
init(u,-50000);
}
else if(uk==2){
tree[u].lzy = 2;
init(u,ur-ul+1);
}
}
inline void pushdown(int u,int ul,int ur){
int mid=(ul+ur)>>1;
maketag(u*2,ul,mid,tree[u].lzy);
maketag(u*2+1,mid+1,ur,tree[u].lzy);
tree[u].lzy = 0;
}

seg query(int u,int l,int r,int ql,int qr){
if(inrange(l,r,ql,qr)) return tree[u];
else if(!outofrange(l,r,ql,qr)){
int mid=(l+r)>>1;
pushdown(u,l,r);
return get(query(u*2,l,mid,ql,qr),query(u*2+1,mid+1,r,ql,qr));
}
else return (seg){0,0,0,0,0};
}

int queryst(int u,int l,int r,int qur){
// assert(u<=n);
pushdown(u,l,r);
if(l==r) return l;
int mid=(l+r)>>1;
// cerr << l << " " << mid << " " << r << "\n";
if(query(1,1,n,l,mid).max>=qur){
// if(0){
// cerr << "1: " << query(u*2,l,mid,l,mid).max << "\n";
return queryst(u*2,l,mid,qur);
}
else if(tree[u*2].back+tree[u*2+1].front>=qur && tree[u*2].back){
// cerr << "2: " << tree[u*2].back+tree[u*2+1].front << "\n";
return mid-tree[u*2].back+1;
}
else{
// cerr << "3: " << query(u*2+1,mid+1,r,mid+1,r).max << "\n";
return queryst(u*2+1,mid+1,r,qur);
}
}

void update(int u,int l,int r,int ul,int ur,int uk){
if(inrange(l,r,ul,ur)) maketag(u,l,r,uk);
else if(!outofrange(l,r,ul,ur)){
int mid=(l+r)>>1;
pushdown(u,l,r);
update(u*2,l,mid,ul,ur,uk);
update(u*2+1,mid+1,r,ul,ur,uk);
pushup(u);
}
}

// #define queryst(x1,x2,x3,x4) 1

void solve(int testID){
cin >> n >> m;
build(1,1,n);
for(int qur=1;qur<=m;qur++){
// cerr << ">>> ";
// for(int i=1;i<=n;i++) cerr<<query(1,1,n,i,i).max<<" ";
// cerr << "\n>>> ";
// cerr << query(1,1,n,1,n).max << "\n";
int op;
cin >> op;
if(op==1){
int x;
cin >> x;
if(query(1,1,n,1,n).max>=x){
int ress=queryst(1,1,n,x);
cout << ress << "\n";
update(1,1,n,ress,ress+x-1,1);
}
else{
cout << "0\n";
}
}
else{
int x,y;
cin >> x >> y;
update(1,1,n,x,x+y-1,2);
}
}
}

signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);

// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
// freopen("PublicDebug.debug", "w", stderr);

// cout << sp();
// cerr << sp();

_t = 1;
// cin >> _t;

for(int ran=0;ran<_t;ran++) solve(ran);

fflush(stdout);
return 0;
}
CPP

USACO 2008 February Gold / 洛谷 P2894 | Hotel
https://gib716-blog.netlify.app/2025/usaco-2008-february-gold-洛谷-p2894-hotel/
作者
Gavin
发布于
2025年1月4日
许可协议