正确的题解

首先我们都知道这题要用线段树做。考虑维护靠左边的answer,靠右边的answer,和整个区间的answer,那么就珂以维护这道题目了。

这里比较复杂的有下传操作和上传操作。

上传

void pushUp(int pos, int l, int r){
seg[pos].ans = max(seg[pos << 1].rans + seg[pos << 1 | 1].lans, max(seg[pos << 1].ans, seg[pos << 1 | 1].ans));
int mid = (l + r) >> 1;
if (seg[pos << 1].ans == mid - l + 1)
seg[pos].lans = seg[pos << 1 | 1].lans + seg[pos << 1].ans;
else
seg[pos].lans = seg[pos << 1].lans;
if (seg[pos << 1 | 1].ans == r - mid)
seg[pos].rans = seg[pos << 1].rans + seg[pos << 1 | 1].ans;
else
seg[pos].rans = seg[pos << 1 | 1].rans;
}

下传

void pushDown(int pos, int l, int r){
if (!seg[pos].lazy){
seg[pos << 1].lazy = seg[pos << 1 | 1].lazy = 0;
int mid = (l + r) >> 1;
seg[pos << 1].ans = seg[pos << 1].lans = seg[pos << 1].rans = mid - l + 1;
seg[pos << 1 | 1].ans = seg[pos << 1 | 1].lans = seg[pos << 1 | 1].rans = r - mid;
}
else if (seg[pos].lazy == 1){
seg[pos << 1].lazy = seg[pos << 1 | 1].lazy = 1;
seg[pos << 1].ans = seg[pos << 1].lans = seg[pos << 1].rans = 0;
seg[pos << 1 | 1].ans = seg[pos << 1 | 1].lans = seg[pos << 1 | 1].rans = 0;
}
seg[pos].lazy = -1;
}

正解代码

#include <cstdio>
#include <algorithm> using namespace std; int read(){
int x = 0; int zf = 1; char ch = ' ';
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
} struct Node{
int ans, lans, rans;
int lazy;
} seg[200000]; void pushUp(int pos, int l, int r){
seg[pos].ans = max(seg[pos << 1].rans + seg[pos << 1 | 1].lans, max(seg[pos << 1].ans, seg[pos << 1 | 1].ans));
int mid = (l + r) >> 1;
if (seg[pos << 1].ans == mid - l + 1)
seg[pos].lans = seg[pos << 1 | 1].lans + seg[pos << 1].ans;
else
seg[pos].lans = seg[pos << 1].lans;
if (seg[pos << 1 | 1].ans == r - mid)
seg[pos].rans = seg[pos << 1].rans + seg[pos << 1 | 1].ans;
else
seg[pos].rans = seg[pos << 1 | 1].rans;
} void pushDown(int pos, int l, int r){
if (!seg[pos].lazy){
seg[pos << 1].lazy = seg[pos << 1 | 1].lazy = 0;
int mid = (l + r) >> 1;
seg[pos << 1].ans = seg[pos << 1].lans = seg[pos << 1].rans = mid - l + 1;
seg[pos << 1 | 1].ans = seg[pos << 1 | 1].lans = seg[pos << 1 | 1].rans = r - mid;
}
else if (seg[pos].lazy == 1){
seg[pos << 1].lazy = seg[pos << 1 | 1].lazy = 1;
seg[pos << 1].ans = seg[pos << 1].lans = seg[pos << 1].rans = 0;
seg[pos << 1 | 1].ans = seg[pos << 1 | 1].lans = seg[pos << 1 | 1].rans = 0;
}
seg[pos].lazy = -1;
} void build(int pos, int l, int r){
if (l == r){
seg[pos].ans = seg[pos].lans = seg[pos].rans = 1;
seg[pos].lazy = -1;
return ;
}
int mid = (l + r) >> 1;
build(pos << 1, l, mid), build(pos << 1 | 1, mid + 1, r);
pushUp(pos, l, r);
} void modify(int pos, int l, int r, int x, int y, int val){
if (x <= l && r <= y){
if (val) seg[pos].ans = seg[pos].lans = seg[pos].rans = 0;
else seg[pos].ans = seg[pos].lans = seg[pos].rans = r - l + 1;
seg[pos].lazy = val;
return ;
}
pushDown(pos, l, r); int mid = (l + r) >> 1;
if (x <= mid) modify(pos << 1, l, mid, x, y, val);
if (y > mid) modify(pos << 1 | 1, mid + 1, r, x, y, val);
pushUp(pos, l, r);
} int query(int pos, int l, int r, int k){
pushDown(pos, l, r); if (l == r) return l;
int mid = (l + r) >> 1;
if (seg[pos << 1].ans >= k) return query(pos << 1, l, mid, k);
if (seg[pos << 1].rans + seg[pos << 1 | 1].lans >= k) return (mid - seg[pos << 1].rans + 1);
else return query(pos << 1 | 1, mid + 1, r, k);
} int main(){
int n = read(), m = read();
build(1, 1, n);
for (int i = 1; i <= m; ++i){
int op = read(), x, y;
if (op == 1){
x = read();
if(seg[1].ans >= x){
int l = query(1, 1, n, x);
printf("%d\n", l);
modify(1, 1, n, l, l + x - 1, 1);
}
else
puts("0");
}
else{
x = read(), y = read();
modify(1, 1, n, x, x + y - 1, 0);
}
}
return 0;
}

提供一种新的得高分思路

这是我发这篇题解的目的,我们看到这熟悉的区间推平操作,很容易就想到了珂朵莉树,也就是我一开始的打法,但是由于数据的原因珂树T了,伤心.jpg。

我们考虑珂朵莉树的查询,显然我们只需要更改一下查询即可

int query(int k){
int l = 1, cnt = 0;
for (set<Node>::iterator it = st.begin(); it != st.end(); ++it){
if (it->val == 1){
l = it->r + 1;
cnt = 0;
}
else{
cnt += it->r - it->l + 1;
if (cnt >= k) return l;
}
}
return -1;
}

我们考虑把连在一起的块的值为零的区间的长度加起来,取第一个满足条件的端点,然后就珂以做出来啦。

可怜的92分代码

#include <cstdio>
#include <vector>
#include <algorithm>
#include <set>
#include <map> using namespace std; int read(){
int x = 0; int zf = 1; char ch = ' ';
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
} //build
struct Node{
int l, r;
mutable bool val;
Node(int a = -1, int b = -1, int c = 0){
l = a, r = b, val = c;
}
bool operator < (const Node &a) const{
return l < a.l;
}
}; set<Node> st; //modify
set<Node>::iterator split(int pos){
set<Node>::iterator it = st.lower_bound(Node(pos));
if (it != st.end() && it->l == pos) return it;
--it; Node tmp = *it; st.erase(it);
st.insert(Node(tmp.l, pos - 1, tmp.val));
return st.insert(Node(pos, tmp.r, tmp.val)).first; //first return iterator
} void assign(int l, int r, bool val){
set<Node>::iterator itr = split(r + 1), itl = split(l);
st.erase(itl, itr);
st.insert((Node){l, r, val});
} //query
int query(int k){
int l = 1, cnt = 0;
for (set<Node>::iterator it = st.begin(); it != st.end(); ++it){
if (it->val == 1){
l = it->r + 1;
cnt = 0;
}
else{
cnt += it->r - it->l + 1;
if (cnt >= k) return l;
}
}
return -1;
} int main(){
int n = read(), m = read(); st.insert((Node){1, n, 0});
while (m--){
int op = read();
if (op == 1){
int x = read(), pos = query(x);
if (pos == -1) puts("0");
else{
printf("%d\n", pos);
assign(pos, pos + x - 1, 1);
}
}
else if (op == 2){
int x = read(), y = read();
assign(x, x + y - 1, 0);
}
}
return 0;
}

[USACO08FEB]Hotel 题解的更多相关文章

  1. USACO08FEB Hotel

    题目传送门 线段树维护区间 线段树结构体 struct zzz{ int l,r,mi; //l为以左端点的为起点的最长子串 //r为以右端点为终点的最长子串 //mi是区间内部的最长子串 }tree ...

  2. POJ3667 Hotel 题解

    和最大子段和的思路是一样的,可以记 \(lmax,rmax,dat\) 分别表示从当前区间最靠左/右的最大连续空子段和当前区间的最大连续空子段. 需要用延迟标记,每次遇到开房操作先ask,如果能找到就 ...

  3. 线段树||BZOJ1593: [Usaco2008 Feb]Hotel 旅馆||Luogu P2894 [USACO08FEB]酒店Hotel

    题面:P2894 [USACO08FEB]酒店Hotel 题解:和基础的线段树操作差别不是很大,就是在传统的线段树基础上多维护一段区间最长的合法前驱(h_),最长合法后驱(t_),一段中最长的合法区间 ...

  4. bzoj4543[POI2014]Hotel

    题目链接 bzoj4543 [POI2014]Hotel 题解 这不是裸地点分嘛 ,我真傻,真的 n^2 这不是是sb题,~滑稽 ~ 枚举点转换为无根树,暴力子树中点的深度 计数转移 令a b c d ...

  5. 浅谈线段树 (例题:[USACO08FEB]酒店Hotel)By cellur925

    今天我们说说线段树. 我个人还是非常欣赏这种数据结构的.(逃)因为它足够优美,有递归结构,有左子树和右子树,还有二分的思想. emm这个文章打算自用,就不写那些基本的操作了... 1° 简单的懒标记( ...

  6. 洛谷P2894 [USACO08FEB]酒店Hotel

    P2894 [USACO08FEB]酒店Hotel https://www.luogu.org/problem/show?pid=2894 题目描述 The cows are journeying n ...

  7. P2894 [USACO08FEB]酒店Hotel

    P2894 [USACO08FEB]酒店Hotel 简单的线段树维护区间信息. 维护三个值,一个是从左端点能拓展的长度,一个是从右端点能脱产的的长度.另一个是整个区间内的最大连续零一长度. 记录这三个 ...

  8. 洛谷 P2894 [USACO08FEB]酒店Hotel 解题报告

    P2894 [USACO08FEB]酒店Hotel 题目描述 The cows are journeying north to Thunder Bay in Canada to gain cultur ...

  9. 线段树【洛谷P2894】 [USACO08FEB]酒店Hotel

    P2894 [USACO08FEB]酒店Hotel 参考样例,第一行输入n,m ,n代表有n个房间,编号为1---n,开始都为空房,m表示以下有m行操作,以下 每行先输入一个数 i ,表示一种操作: ...

随机推荐

  1. pycharm运行测试用例遇到错误:ZeroDivisionError: float division by zero的原因

    运行测试用例报错:ZeroDivisionError: float division by zero 一般是因为测试用例模块命名没有以test开头,导致unittest找不到用例,用例总数为0,导致除 ...

  2. 【EW系列】SAP EWM模块-EWM的常用T-CODE整理

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[EWM系列]SAP EWM模块-EWM的常用T ...

  3. 【Qt开发】Qt中图像的显示与基本操作

    Qt可显示基本的图像类型,利用QImage.QPxmap类可以实现图像的显示,并且利用类中的方法可以实现图像的基本操作(缩放.旋转). 1. Qt可显示的图像类型 参考Qt的帮助文档,可支持的类型,即 ...

  4. ELK7.4.0分析nginx json日志

    ELK7.4.0单节点部署 环境准备 安装系统,数据盘设置为/srv 内核优化参考 我们需要创建elk专用的账号,并创建所需要的目录并授权 useradd elk; mkdir /srv/{app,d ...

  5. 华南理工大学 “三七互娱杯” G HRY and tree

    https://ac.nowcoder.com/acm/contest/874/G 题目大意:对于一个连通图,现在定义两个点的贡献为连接两点的路径上最大的权值 求任意两个点贡献的和 这个题看懂花了我很 ...

  6. Quartz任务调度的测试Demo1(含有配置文件的demo)

    Quartz是一个作业任务调度的框架,所在项目组中“消息推送模块”使用到此框架,于是写个demo熟悉下quart的用法: 使用Spring框架来集成Quartz的任务调度任务. 1.搭建Spring框 ...

  7. strtoul()要优于atoi()函数---C语言

    strtoul():将字符串转为长整型整数 atoi():将字符串转为整型整数 在32位STM32中,int是32位的,如果字符串是“3123456789”,大于0x7fff fff,用atoi()函 ...

  8. tz汇报

    不爽,不满意,存在太多Bug,汇报前的了解不充分,了解到了有那些领导参加,但是没有具体了解领导的时间安排,没有按照领导的时间调整汇报提纲及思路,汇报到1个半小时,领导需要参加会议,提前离开,没能够与领 ...

  9. spring cloud zuul过滤器修改requestURI 忽略大小写

    通过zuul网关处理requestURI可以做很多事情,如对uri的解密,转发,大小写转化等. 这里对URI做一个简单的大小写的转化. 写一个filter实现ZuulFilter: package c ...

  10. 14-jquery元素节点操作

    **创建节点** ```var Div = $('<div>');var Div2 = $('<div>这是一个div元素</div>');``` **插入节点** ...