题目传送:Hotel
思路:线段树,区间合并,区间替换,查询最左断点,看胡浩版本的线段树好几天了,今天看这个看了好久,慢慢来吧,具体都写在注释里了
AC代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <vector> #include <map> #include <set> #include <deque> #include <cctype> #define LL long long #define INF 0x7fffffff using namespace std; int n, m; const int maxn = 50005; int sum[maxn << 2];//用于保存当前结点所代表区间的最长连续空房间 int lsum[maxn << 2];//用于保存包含当前结点最左房间在内的一段最长连续空房间 int rsum[maxn << 2];//用于保存包含当前结点最右房间在内的一段最长连续空房间 int lazy[maxn << 2];//延迟标记 void build(int l, int r, int rt) {//建树 sum[rt] = lsum[rt] = rsum[rt] = r - l + 1;//初始的时候都是空房间 lazy[rt] = -1; if(l == r) return; int mid = (l + r) >> 1; build(l, mid, rt << 1); build(mid + 1, r, rt << 1 | 1); } void pushdown(int rt, int m) {//往下更新 if(lazy[rt] != -1) {//需要往下更新 lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt]; //把这段房间置为空或置为住满 lsum[rt << 1] = rsum[rt << 1] = sum[rt << 1] = lazy[rt] ? 0 : m - (m >> 1); lsum[rt << 1 | 1] = rsum[rt << 1 | 1] = sum[rt << 1 | 1] = lazy[rt] ? 0 : (m >> 1); lazy[rt] = -1; } } void pushup(int rt, int m) {//往上更新 lsum[rt] = lsum[rt << 1];//父节点的左区间先赋值为左孩子的左区间 rsum[rt] = rsum[rt << 1 | 1];//父节点的右区间先赋值为右孩子的右区间 if(lsum[rt] == m - (m >> 1)) lsum[rt] += lsum[rt << 1 | 1];//如果左区间满了则继续往右扩张 if(rsum[rt] == (m >> 1)) rsum[rt] += rsum[rt << 1];//如果右区间满了则继续往左扩张 //父节点的最大连续空房间取决于左区间,右区间和中间那个区间的最大值 sum[rt] = max(rsum[rt << 1] + lsum[rt << 1 | 1], max(sum[rt << 1], sum[rt << 1 | 1])); } void update(int L, int R, int c, int l, int r, int rt) {//更新 if(L <= l && r <= R) { sum[rt] = lsum[rt] = rsum[rt] = c ? 0 : r - l + 1; lazy[rt] = c; return; } pushdown(rt, r - l + 1); int mid = (l + r) >> 1; if(L <= mid) update(L, R, c, l, mid, rt << 1); if(mid < R) update(L, R, c, mid + 1, r, rt << 1 | 1); pushup(rt, r - l + 1); } int query(int w, int l, int r, int rt) {//查询 if(l == r) { return l; } pushdown(rt, r - l + 1); int mid = (l + r) >> 1; if(sum[rt << 1] >= w) return query(w, l, mid, rt << 1); else if(rsum[rt << 1] + lsum[rt << 1 | 1] >= w) { return mid - rsum[rt << 1] + 1;//分而治之的思想关键,这里用于求出房间数大于1的所有答案 } else return query(w, mid + 1, r, rt << 1 | 1); } int main() { scanf("%d %d", &n, &m); build(1, n, 1);//建树 for(int i = 0; i < m; i ++) { int op, a, b; scanf("%d", &op); if(op == 1) { scanf("%d", &a); if(sum[1] < a) puts("0"); else { int pos = query(a, 1, n, 1); printf("%d\n", pos); update(pos, pos + a - 1, 1, 1, n, 1); } } else { scanf("%d %d", &a, &b); update(a, a + b - 1, 0, 1, n, 1); } } return 0; }
POJ - 3667 - Hotel (线段树 - 区间合并)
原文地址:http://blog.csdn.net/u014355480/article/details/45748469