Though I came up with a solution using PriorityQueue and BST, this problems still confuses me. To make it more clear, I went through it several times and investigated several good solutions on this forum.
Here is my explanation which tries to make understanding this easier and may help you write a bugfree solution quickly.
When visiting all start points and end points in order:
Observations:

If a position is shadowed by other buildings
1. height of that building is larger than the building to which current position belong; 2. the start point of that building must be smaller(or equal to) than this position; 3. the end point of that building must be larger(or equal to) than this position;
Tus we have:
1. when you reach a start point, the height of current building immediately
takes effect which means it could possibly affect the contour or shadow
others when mixed with other following buildings;
2. when you reach a end point, the height of current building will stop its
influences;
3. our target exists at the position where height change happens and there
is nothing above it shadowing it;
Obviously, to implement the idea that 'current height takes effect' and 'find out whether current height is shadowed by other buildings', we need a mechanism to store current taking effect heights, meanwhile, figure out which one is the maximum, delete it if needed efficiently, which hints us to use a priority queue or BST.
Thus, our algorithm could be summarised in following pseudo code:
for position in sorted(all start points and all end points)
if this position is a start point
add its height
else if this position is a end point
delete its height
compare current max height with previous max height, if different, add
current position together with this new max height to our result, at the
same time, update previous max height to current max height;
To implement this algorithm, here are some concrete examples:
 In my implementation, I use a PriorityQueue to store end point values when visiting a start point, and store the [height, end point value] into a TreeMap. Thus:
 when moving to next start point value, I can compare the next start point value with elements in PriorityQueue, thus achieving visiting all start points and end points in order(exploits the fact that start points are already sorted);
 Meantime, I can get current max height from TreeMap in O(logn);
 However, to delete a height when visiting a end point, I have to use 'map.values.remove()' which is a method defined in Collection interface and tends to be slower(O(n) is this case, plz correct me if I'm wrong);
My code can be found at https://leetcode.com/discuss/62617/shortandcleanjavasolutionheapandtreemap
 Following is wujin's implementation(plz refer to https://leetcode.com/discuss/54201/shortjavasolution). This one is quite straightforward, clean and clever.
Firstly, please notice what we need to achieve:
1. visit all start points and all end points in order;
2. when visiting a point, we need to know whether it is a start point or a
end point, based on which we can add a height or delete a height from
our data structure;
To achieve this, his implementation:
1. use a int[][] to collect all [start point,  height] and [end point, height]
for every building;
2. sort it, firstly based on the first value, then use the second to break
ties;
Thus,
1. we can visit all points in order;
2. when points have the same value, higher height will shadow the lower one;
3. we know whether current point is a start point or a end point based on the
sign of its height;
His code is as follows(clear and concise) as reference with my comment(again, https://leetcode.com/discuss/54201/shortjavasolution):
public List<int[]> getSkyline(int[][] buildings) {
List<int[]> result = new ArrayList<>();
List<int[]> height = new ArrayList<>();
for(int[] b:buildings) {
// start point has negative height value
height.add(new int[]{b[0], b[2]});
// end point has normal height value
height.add(new int[]{b[1], b[2]});
}
// sort $height, based on the first value, if necessary, use the second to
// break ties
Collections.sort(height, (a, b) > {
if(a[0] != b[0])
return a[0]  b[0];
return a[1]  b[1];
});
// Use a maxHeap to store possible heights
Queue<Integer> pq = new PriorityQueue<>((a, b) > (b  a));
// Provide a initial value to make it more consistent
pq.offer(0);
// Before starting, the previous max height is 0;
int prev = 0;
// visit all points in order
for(int[] h:height) {
if(h[1] < 0) { // a start point, add height
pq.offer(h[1]);
} else { // a end point, remove height
pq.remove(h[1]);
}
int cur = pq.peek(); // current max height;
// compare current max height with previous max height, update result and
// previous max height if necessary
if(prev != cur) {
result.add(new int[]{h[0], cur});
prev = cur;
}
}
return result;
}
Hopefully now, you can write a good solution in a blink with good understanding...