Gym 100733J Summer Wars 题解:灵活运用扫描线的思想

题意:

给你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;
}
时间: 2024-10-01 06:05:03

Gym 100733J Summer Wars 题解:灵活运用扫描线的思想的相关文章

Gym - 100781G Goblin Garden Guards (扫描线)

题意: n 只哥布林,每只哥布林都有一个位置坐标. m 个炮台,每个炮台都有一个位置坐标和一个攻击半径. 如果一个哥布林在任何一个炮台的攻击范围内,都会被杀死. 求最后没有被杀死的哥布林的数量. 这题暴力加一些小小的优化可以爆过去...然后场上并不敢试. 标算是扫描线.炮台攻击范围内的每个横坐标都拉一个扫描线,把线的两端的点和哥布林的点一起加进一个数组. 然后排序,就会发现能被杀死的哥布林的点在一根线的两个端点之间. 直接扫一遍统计答案就可以了.注意存点的数组要开够. 另外就是...排序的时候

Gym 100431E Word Cover 题解:KMP神用

题意: 给你一个串,问你他的每个前缀的最小重复单元,其中单元是可以重叠的,最后按顺序输出即可.比如样例中abaabaa的最小重复单元为abaa,所以相应输出为4. 样例: input : abaabaababa outpit:1 2 3 4 5 3 4 5 3 10 3 kmp过程就不用多说了,现在我们利用next数组的性质来对问题进行求解. 我们首先用一个ans[maxn]数组来记录最后的答案,且我们的字符串下标从0开始,显然,我们ans[i]的最大值为i+1,我们因此也用此值对其进行初始化.

[题解/模板]扫描线

luogu_P1856矩形周长 #include<bits/stdc++.h> #define ls (x<<1) #define rs (x<<1|1) //#define mid (l+r>>1) using namespace std; const int maxn=5009; const int maxm=10009; int n,ans; struct square{ int xa,xb,ya,yb; }r[maxn]; int hsh[maxn&

uva 11983 Weird Advertisement 扫描线

Weird Advertisement Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=18802 Description 2DPlaneLand is a land just like a huge 2D plane. The range of X axis is 0 to 109 and the range ofY axis

POJ1151 Atlantis 【扫描线】

Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 16882   Accepted: 6435 Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of

POJ1151 Atlantis 【扫描线】+【线段树】+【离散化】

Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 16882   Accepted: 6435 Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of

Gym 101606F - Flipping Coins - [概率DP]

题目链接:https://codeforc.es/gym/101606/problem/F 题解: 假设 $f[i][j]$ 表示抛 $i$ 次硬币,有 $j$ 个硬币正面朝上的概率. 所以只有两种挑选硬币的情况: 1.正面硬币数量为 $[0,n-1]$,选择反面硬币抛,则正面硬币数量比原本增加 $1$ 或者不变. 2.正面硬币数量为 $n$,随便选择一个硬币抛,则正面硬币数量比原本减少 $1$ 或者不变. 因此可得状态转移方程: 对于 $j<n$,有 f[i+1][j+1]+=f[i][j]*

[CF612D] The Union of k-Segments(排序,扫描线)

题目链接:http://codeforces.com/contest/612/problem/D 题意:给n条线段,问覆盖了k次的区间有几个. 扫描线的思想,首先想到的是从左到右扫一遍,遇到出现被覆盖k次的端点,则开始计数,直到覆盖次数小于k为止. 其实可以用线段树做这道题,但是还有更巧妙的办法: 将左端点看作"入",右端点看作"出".每一个线段都是一个区间从入到出,入指的是覆盖次数+1,出指的是覆盖次数-1. 按照左端点升序排列,每遇到一个"入"

bzoj 3225: [Sdoi2008] 立方体覆盖 题解

[原题] 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec  Memory Limit: 128 MB Submit: 51  Solved: 36 [Submit][Status] Description A君近日为准备省队选拔.特意进行了数据结构的专项训练.训练过程中就遇到了"矩形面积并"这道经典问题.即:给出N个各边与坐标轴平行(垂直)的矩形,求矩形覆盖的面积之和. A君按纵坐标建立线段树后按横坐标扫描计算.轻易AC了这道题,时间复杂度为O(Nlog