一、题目
1、题目描述
在二维平面上的 x 轴上,放置着一些方块。
给你一个二维整数数组 positions ,其中 
    
     
      
       
        p
       
       
        o
       
       
        s
       
       
        i
       
       
        t
       
       
        i
       
       
        o
       
       
        n
       
       
        s
       
       
        [
       
       
        i
       
       
        ]
       
       
        =
       
       
        [
       
       
        l
       
       
        e
       
       
        f
       
       
        
         t
        
        
         i
        
       
       
        ,
       
       
        s
       
       
        i
       
       
        d
       
       
        e
       
       
        L
       
       
        e
       
       
        n
       
       
        g
       
       
        t
       
       
        
         h
        
        
         i
        
       
       
        ]
       
      
      
       positions[i] = [left_i, sideLength_i]
      
     
    positions[i]=[lefti,sideLengthi] 表示:第 i 个方块边长为 
    
     
      
       
        s
       
       
        i
       
       
        d
       
       
        e
       
       
        L
       
       
        e
       
       
        n
       
       
        g
       
       
        t
       
       
        
         h
        
        
         i
        
       
      
      
       sideLength_i
      
     
    sideLengthi ,其左侧边与 x 轴上坐标点 
    
     
      
       
        l
       
       
        e
       
       
        f
       
       
        
         t
        
        
         i
        
       
      
      
       left_i
      
     
    lefti 对齐。
每个方块都从一个比目前所有的落地方块更高的高度掉落而下。方块沿 y 轴负方向下落,直到着陆到 另一个正方形的顶边 或者是 x 轴上 。一个方块仅仅是擦过另一个方块的左侧边或右侧边不算着陆。一旦着陆,它就会固定在原地,无法移动。
在每个方块掉落后,你必须记录目前所有已经落稳的 方块堆叠的最高高度 。
返回一个整数数组 ans ,其中 ans[i] 表示在第 i 块方块掉落后堆叠的最高高度。
示例1:
 
输入:positions = [[1,2],[2,3],[6,1]]
输出:[2,5,5]
解释:
第 1 个方块掉落后,最高的堆叠由方块 1 组成,堆叠的最高高度为 2 。
第 2 个方块掉落后,最高的堆叠由方块 1 和 2 组成,堆叠的最高高度为 5 。
第 3 个方块掉落后,最高的堆叠仍然由方块 1 和 2 组成,堆叠的最高高度为 5 。
因此,返回 [2, 5, 5] 作为答案。
 
示例2:
输入:positions = [[100,100],[200,100]]
输出:[100,100]
解释:
第 1 个方块掉落后,最高的堆叠由方块 1 组成,堆叠的最高高度为 100 。
第 2 个方块掉落后,最高的堆叠可以由方块 1 组成也可以由方块 2 组成,堆叠的最高高度为 100 。
因此,返回 [100, 100] 作为答案。
注意,方块 2 擦过方块 1 的右侧边,但不会算作在方块 1 上着陆。
 
2、基础框架
class Solution {
public:
    vector<int> fallingSquares(vector<vector<int>>& positions) {
    }
};
 
3、原题链接
699. 掉落的方块
二、解题报告
1、思路分析
利用线段树。
 题目分析:比如第一个方块[1,2],对应成线段树就是区间[1, 3) (靠着1,长度为2,所以能到达x轴的3位置,但是为了防止贴边,所以区间左闭右开)每个位置的值加2。

 如果有一个新的方块落下来[left, sideLength],要先查询 [left, left + sideLength) 这个范围上的最大高度值 maxH,就知道落到这个高度后不能往下再落了,将[left, left + sideLength]区间上的所有高度全部更新为 maxH + sideLength,这个区间上原先的值为多少不再关心。
整体而言,就是一个 更新 + 查询max的线段树
2、时间复杂度
O ( n l o g n ) O(nlogn) O(nlogn)
3、代码详解
- C++
 
class Solution {
public:
    class SegmentTree {
    private:
        int *maxH;
        int *change;
        bool *updateMark;
    public:
        //线段树初始化
        SegmentTree(int size) { //x轴上的数开始都为0,不存在数组
            int n = size + 1;
            maxH = new int[n << 2]();
            change = new int[n << 2]();
            updateMark = new bool[n << 2]();
        }
    private:
        //根节点的最大值
        void pushUp(int rt) { 
            maxH[rt] = max(maxH[rt << 1], maxH[rt << 1 | 1]); //从左右子树中得到最大值
        }    
        //向下一级分发任务
        void pushDown(int rt, int ln, int rn) {
            if (updateMark[rt]) {
                updateMark[rt << 1] = true;
                updateMark[rt << 1 | 1] = true;
                change[rt << 1] = change[rt];
                change[rt << 1 | 1] = change[rt];
                maxH[rt << 1] = change[rt];
                maxH[rt << 1 | 1] = change[rt];
                updateMark[rt] = false;
            }
        }
    public:
        //更新
        void update(int L, int R, int C, int l, int r, int rt) {
            if (L <= l && r <= R) {
                change[rt] = C;
                updateMark[rt] = true;
                maxH[rt] = C;
                return ;
            }
            int mid = (l + r) >> 1;
            pushDown(rt, mid - l + 1, r - mid);
            if (L <= mid) {
                update(L, R, C, l, mid, rt << 1);
            }
            if (R > mid) {
                update(L, R, C, mid + 1, r, rt << 1 | 1);
            }
            pushUp(rt);
        }
        //查询
        int query(int L, int R, int l, int r, int rt) {
            if (L <= l && r <= R) {
                return maxH[rt];
            }
            int left = 0;
            int right = 0;
            int mid = (l + r) >> 1;
            pushDown(rt, mid - l + 1, r - mid);
            if (L <= mid) {
                left = query(L, R, l, mid, rt << 1);
            }
            if (R > mid) {
                right = query(L, R, mid + 1, r, rt << 1 | 1);
            }
            return max(left, right);
        }
    };
    unordered_map<int, int> index(vector<vector<int>>& positions) {
        set<int> pos;
        for (vector<int> &arr: positions) {
            pos.insert(arr[0]);
            pos.insert(arr[0] + arr[1] - 1);
        }
        unordered_map<int, int> _map;
        int count = 0;
        for (int index : pos) {
            _map[index] = ++count;
        }
        
        return _map;
    }
    vector<int> fallingSquares(vector<vector<int>>& positions) {
        unordered_map<int, int> _map = index(positions);
        int n = _map.size();
        SegmentTree *st = new SegmentTree(n);
        int maxH = 0;
        vector<int> res;
        for (vector<int> &arr : positions) {
            int L = _map[arr[0]];
            int R = _map[arr[0] + arr[1] - 1]; 
            int height = st->query(L, R, 1, n, 1) + arr[1]; 
            maxH = max(maxH, height);
            res.push_back(maxH);
            st->update(L, R, height, 1, n, 1);
        }
        return res;
    }
};
 
- Java
 
class Solution {
    public static class SegmentTree {
		private int[] max;
		private int[] change;
		private boolean[] update;
		public SegmentTree(int size) {
			int N = size + 1;
			max = new int[N << 2];
			change = new int[N << 2];
			update = new boolean[N << 2];
		}
		private void pushUp(int rt) {
			max[rt] = Math.max(max[rt << 1], max[rt << 1 | 1]);
		}
		// ln表示左子树元素结点个数,rn表示右子树结点个数
		private void pushDown(int rt, int ln, int rn) {
			if (update[rt]) {
				update[rt << 1] = true;
				update[rt << 1 | 1] = true;
				change[rt << 1] = change[rt];
				change[rt << 1 | 1] = change[rt];
				max[rt << 1] = change[rt];
				max[rt << 1 | 1] = change[rt];
				update[rt] = false;
			}
		}
		public void update(int L, int R, int C, int l, int r, int rt) {
			if (L <= l && r <= R) {
				update[rt] = true;
				change[rt] = C;
				max[rt] = C;
				return;
			}
			int mid = (l + r) >> 1;
			pushDown(rt, mid - l + 1, r - mid);
			if (L <= mid) {
				update(L, R, C, l, mid, rt << 1);
			}
			if (R > mid) {
				update(L, R, C, mid + 1, r, rt << 1 | 1);
			}
			pushUp(rt);
		}
		public int query(int L, int R, int l, int r, int rt) {
			if (L <= l && r <= R) {
				return max[rt];
			}
			int mid = (l + r) >> 1;
			pushDown(rt, mid - l + 1, r - mid);
			int left = 0;
			int right = 0;
			if (L <= mid) {
				left = query(L, R, l, mid, rt << 1);
			}
			if (R > mid) {
				right = query(L, R, mid + 1, r, rt << 1 | 1);
			}
			return Math.max(left, right);
		}
	}
    public HashMap<Integer, Integer> index(int[][] positions) {
		TreeSet<Integer> pos = new TreeSet<>();
		for (int[] arr : positions) {
			pos.add(arr[0]);
			pos.add(arr[0] + arr[1] - 1);
		}
		HashMap<Integer, Integer> map = new HashMap<>();
		int count = 0;
		for (Integer index : pos) {
			map.put(index, ++count);
		}
		return map;
	}
    public List<Integer> fallingSquares(int[][] positions) {
        HashMap<Integer, Integer> map = index(positions);
		int N = map.size();
		SegmentTree segmentTree = new SegmentTree(N);
		int max = 0;
		List<Integer> res = new ArrayList<>();
		// 每落一个正方形,收集一下,所有东西组成的图像,最高高度是什么
		for (int[] arr : positions) {
			int L = map.get(arr[0]);
			int R = map.get(arr[0] + arr[1] - 1);
			int height = segmentTree.query(L, R, 1, N, 1) + arr[1];
			max = Math.max(max, height);
			res.add(max);
			segmentTree.update(L, R, height, 1, N, 1);
		}
		return res;
    }
}
                













![P1055 [NOIP2008 普及组] ISBN 号码————C++](https://img-blog.csdnimg.cn/e5f6f20a8f304e5e9f4cd1f5b801d6b8.png)




