poj 3667 线段树前后缀区间 Hotel
来源:互联网 发布:java分布式锁原理 编辑:程序博客网 时间:2024/05/27 20:07
【题意】
一共有n个空位,初始全为空,会有两种操作,一种是询问是否有r个连续的空位,若有,则将最左端有r个连续的空位的地方全部填满,若没有则不填,另一种是将从u开始的d个位置全部清空
【输入】
第一行两个数n、m(<=50000),表示n个空位,m次操作
接下来m行每行表示一次操作,
若该行第一个数字为1,接下来是一个数字,表示操作一
若该行第一个数字为2,接下来是两个数字,表示操作二
【输出】
一共有n个空位,初始全为空,会有两种操作,一种是询问是否有r个连续的空位,若有,则将最左端有r个连续的空位的地方全部填满,若没有则不填,另一种是将从u开始的d个位置全部清空
【输入】
第一行两个数n、m(<=50000),表示n个空位,m次操作
接下来m行每行表示一次操作,
若该行第一个数字为1,接下来是一个数字,表示操作一
若该行第一个数字为2,接下来是两个数字,表示操作二
【输出】
对于每个操作一,若存在r个连续的空位,则输出最靠左的r个连续空位的起点,若不存在则输出0
解:
用lsum表示当前区间最长连续前缀的长度,rsum表示当前区间最长连续后缀的长度,msum表示本个区间最长连续段的长度。重点是还有一个cover,-1表示这个区间既有非空的,又有空的; 1 表示整个当前区间都满了; 0 表示整个区间都空了。 就是lazy。
查询的时候,首先,得满足有这样连续的长度。其次:
如果当前区间前缀长度就大于等于我们想要的长度的话,就返回左端点。
如果左孩子的最长长度>=wanted的话,就去左孩子里面找。
如果包含m的连续区间>=wanted的话,就直接返回左孩子后缀的最左端。
不然,就只能去右孩子里面找了。
做题过程:
开始没有cover,没有push_dn,就只有一个push_up。 想来更新的时候不是没有更新到底吗,也就是说孩子还没更新呢,所以一定得有cover的呀。
现在再一想,果然表示当前区间是线段树的根本,我怎么给忘了呢。。。
/*Pro: 0Sol:date:*/#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <set>#include <vector>#define maxn 50010#define lson l,m , rt << 1#define rson m + 1, r , rt << 1 | 1#define ls rt << 1#define rs rt << 1 | 1int n,Q,a,b,op;using namespace std;int lsum[maxn << 2], rsum[maxn << 2], msum[maxn << 2], cover[maxn << 2];void build(int l, int r, int rt){ lsum[rt] = rsum[rt] = msum[rt] = r - l + 1; cover[rt] = 0;// if(l == r) return ; int m = (l + r) >> 1; build(lson); build(rson);}void push_dn(int rt, int m){ if(cover[rt] != -1){ cover[ls] = cover[rs] = cover[rt]; lsum[ls] = rsum[ls] = msum[ls] = cover[rt] == 0? m - (m >> 1): 0;// lsum[rs] = rsum[rs] = msum[rs] = cover[rt] == 0? (m >> 1): 0; cover[rt] = -1; }}void push_up(int rt,int m){ lsum[rt] = lsum[ls]; rsum[rt] = rsum[rs]; if(lsum[ls] == m - (m >> 1)) lsum[rt] += lsum[rs]; if(rsum[rs] == m >> 1) rsum[rt] += rsum[ls]; msum[rt] = max(msum[ls] , msum[rs]); msum[rt] = max(msum[rt], rsum[ls] + lsum[rs]);}//int query(int dis, int l, int r, int rt){//notOnlySuccess 的版本, 有点不是很懂。。。// if(l == r) return l;//// push_dn(rt, r - l + 1);// int m = (l + r) >> 1;// if(msum[ls] >= dis) return query(dis,lson);// if(rsum[ls] + lsum[rs] >= dis) return m - rsum[ls] + 1;// return query(dis, rson);//}int query(int dis, int l, int r, int rt){//寻找长度为dis的最左边的区间的左端点,于是就自己借鉴着改了一改,A了 if(lsum[rt] >= dis) return l; push_dn(rt, r - l + 1); int m = (l + r) >> 1; if(msum[ls] >= dis) return query(dis,lson); if(rsum[ls] + lsum[rs] >= dis) return m - rsum[ls] + 1; return query(dis, rson);}void update(int L,int R, int sign, int l, int r, int rt){ if(L <= l && r <= R){ lsum[rt] = rsum[rt] = msum[rt] = sign == 0 ? r - l + 1 : 0; cover[rt] = sign; return ; }push_dn(rt,r - l + 1); int m = (l + r) >> 1; if(L <= m) update(L,R,sign,lson); if(R > m) update(L,R,sign,rson); push_up(rt,r - l + 1);//}int main(){ while(~scanf("%d%d",&n,&Q)){ build(1,n,1); for(int i = 0; i < Q; i ++){ scanf("%d",&op); if(op == 1){ scanf("%d",&a); if(msum[1] < a) puts("0"); else{ int st = query(a,1,n,1); printf("%d\n", st); update(st, st + a - 1, 1 ,1, n, 1); } }else{ scanf("%d%d",&a,&b); update(a, a + b - 1, 0, 1, n, 1);//0 表示没住人 } } }return 0;}
- poj 3667 线段树前后缀区间 Hotel
- POJ 3667 Hotel 线段树区间合并
- poj 3667 Hotel 线段树区间合并
- POJ 3667 Hotel 线段树 区间合并
- Poj 3667 Hotel 线段树 区间合并
- poj 3667 Hotel(线段树区间分配)
- POJ 3667-hotel(线段树区间合并)
- POJ 3667 Hotel. (线段树 区间合并)
- 【线段树】POJ 3667 Hotel 区间合并
- POJ 3667 Hotel ( 线段树区间合并 )
- 线段树 区间合并 poj 3667 Hotel
- POJ 3667 Hotel 线段树 区间合并
- poj 3667 Hotel(线段树区间更新)
- POJ - 3667 Hotel (线段树 + 区间合并)
- POJ 3667 Hotel 【线段树 区间合并】
- poj 3667 Hotel 【线段树区间合并】
- POJ 3667Hotel 线段树区间合并
- POJ 3667 - Hotel(线段树+区间合并)
- 如何在NCBI实现大批量数据的一一对应
- I/O完成端口简单例子
- HDU 4288 Coder(线段树或者暴力vector)#by zh
- Java强引用、 软引用、 弱引用、虚引用
- Frame Stacking 很好的拓扑排序题 hoj&poj
- poj 3667 线段树前后缀区间 Hotel
- HDU 1205 注意使用64位精度,否则WA
- android 检测网络状态
- php将汉字转化为拼音和获取ip归属地接口
- javascript获取和设置FCKeditor内容
- 单向链表C++
- win7+vs2010+VTK
- CEO、COO、CFO、CTO、CIO是什么意思
- ecshop在php5.3以上的错误number_format() 解决方案