1. 程式人生 > >Gym 100733J Summer Wars 題解:靈活運用掃描線的思想

Gym 100733J Summer Wars 題解:靈活運用掃描線的思想

ace ng- 最大值 掃描線 例如 main post 集合 i++

題意:


給你n個點,m個橫著的線段。你能夠橫移這些線段,可是這些線段的相對位置不能改變。假設一個點,在它的正上方和和正下方都有線段(包含線段的終點)。則這個點被視為被“屏蔽”。問通過隨意平移我們能夠遮住最多的點的數量。

解題思路:

首先把全部的點向右平移1000000個單位。然後那些線段位置不變,我們開始平移這些點,這樣我們保證點向左移動的距離肯定是一個正數,方便處理。
這樣我們僅僅要求出每一個點向左移動的距離後能夠滿足題目條件的集合W。然後在求出某個距離值在全部的集合中出現最多次數的就可以,這個次數即是答案。

而我們重點就是求這個集合W。假設暴力的尋找。題目數據範圍為1000000,點數1000,兩者相乘的復雜度顯然不可行,這裏我們就要運用掃描線的思想了。
我們把條線段看成是兩個點:入點 和 出點

比方一條(x1,y) - (x2,y)的線段。我們在(x1,y)的位置上標記一個1。在(x2+1,y)的位置上標記一個-1,然後依照橫坐標從左到右的順序掃過這些點,事實上就是掃描線的思想了。然後在可行的範圍內我們的P數組位置上+1。然後找出P中的最大值就可以。


這裏在更新P數組的時候我們也不能夠直接暴力更新,比方我們要更新區間[l,r]區間都+1。我們僅僅要在P[l]位置上+1,在P[r+1]的位置上-1,然後最後一起更新就可以。



代碼例如以下:


#include <bits/stdc++.h>

using namespace std;

int N, M;
pair<int, int> A[1000]; //儲存點的坐標

struct event {	//儲存線段轉化後的點,tp = 1 表示入點,tp = -1 表示出點
	int x, y, tp;
	bool operator< (const event& other) const {
		return x < other.x;
	}
};

event B[2015];
int P[2000016];	//維護答案的數組

int main() {
	//freopen("in.in", "r", stdin);
	//freopen("out.out", "w", stdout);
	scanf("%d%d", &N, &M);
	for (int i = 0; i < N; i++) {
		scanf("%d%d", &A[i].second, &A[i].first);	//題目好坑啊,是依照y,x的順序給的坐標
		A[i].first += 1000000;
	}
	int y, x1, x2;
	for (int i = 0; i < M; i++) {
		scanf("%d%d%d", &y, &x1, &x2);
		B[i * 2] = (event) {x1, y, 1};
		B[i * 2 + 1] = (event) {x2 + 1, y, -1};
	}
	sort(B, B + 2 * M);		//掃描前要先對線段轉化的點依照橫坐標進行排序
	multiset<int> s; s.clear();		//s儲存現在區間全部線段的縱坐標的集合
	for (int i = 0; i < N; i++) {
		int last = -1;
		for (int j = 0, k; j < 2 * M; j = k) {
			for (k = j; k < 2 * M && B[k].x == B[j].x; k++) {
				if (B[k].tp == -1)
					s.erase(s.find(B[k].y));
				else
					s.insert(B[k].y);
			}
			if (last != -1) P[A[i].first - B[j].x + 1]++, P[A[i].first - last + 1]--;		//O(1)更新P數組

			if (s.empty() || *s.begin() > A[i].second || *s.rbegin() < A[i].second)	//表示現在橫坐標下第i個點不能滿足題意
				last = -1;
			else
				last = B[j].x;		//記錄上次滿足的橫坐標
		}
	}
	int ans = 0;
	for (int i = 1; i <= 2000015; i++)
		ans = max(ans, P[i] += P[i - 1]);	//利用更新的信息同一時候尋找答案,即最大值
	printf("%d\n", ans);
	return 0;
}



Gym 100733J Summer Wars 題解:靈活運用掃描線的思想