首页 > 其他分享 >[ABC211F] Rectilinear Polygons 题解

[ABC211F] Rectilinear Polygons 题解

时间:2024-04-04 10:56:03浏览次数:30  
标签:val int 题解 ABC211F yy ++ xx que Rectilinear

[ABC211F] Rectilinear Polygons 题解

思路什么的上一篇题解已经写的非常明白了,这里只是提供一个补充 & 另一个实现的方法。

思路解析

先说结论:扫描线。顾名思义,扫描线的本质就是用一条线沿着 \(x\) 或 \(y\) 轴扫过去,每碰到一条边就记录一下加边后是面积是增加还是减少,然后用树状数组或线段树统计。由于我们并不需要知道整张图所有的位置的值,我们就只需要求出来扫描线所在的那一行 or 列每一个点的值即可。

这里就不过多解释,如果没有学过扫描线建议去做一下模板题,推荐看第一篇题解。

接下来就是本题的重点,该如何把不规则图形存下来。如下图,我们先把图上的竖边找出来,同时给点的顺序标一个号。

可见四条边中左边三条的权值都是增加的,只有右边一条是减少的。我们寻找边上的两点和权值的关系,可以发现,由于是点顺序输入的,所以每一条正边权的边的两点中编号较小的点 \(y\) 值也是更小的,而每一条边的两点中编号较小的点的编号一定是奇数。因此我们可以给每一条边都判断两点编号的大小来决定是用正边权还是负边权。

实现

我们根据以上所说的方式存好每一条边,然后将边按 \(x\) 的值排序,满足扫描线的性质。对于询问我们将询问离线下来,同样按 \(x\) 排序,这样我们在进行加边之前判断当前扫描线是否已经处理了所有 \(x\) 小于当前询问的 \(x\) 的边,若已经处理完就更新答案。

接下来有几点注意事项。

  • 题目中的输入点的顺序不一定满足我们想要的输入顺序,所以我们需要自己找到一个在 \(x\) 最小的情况下 \(y\) 也最小的点做编号为 \(1\) 的点。
  • 由于我们只需要知道一个点被覆盖的次数,所以可以将模板中的线段树换成树状数组区修单查。
  • 由于我们需要先把当前 \(x\) 轴上的边加完再统计询问,所以我们要在所有边的最后加上一个 \(x=\inf,val=0\) 的边,这样就能防止最后有几个点没有处理到。

code

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 1e5;
int n, m, xx[N], yy[N], tv[N], q, c[N], ans[N];
struct side {
	int x, ya, yb, val;
};
struct point {
	int x, ya, yb; 
};
struct query {
	int x, y, p;
};
void add(int x, int y) {
	for(; x <= M; x += (x & -x)) {
		c[x] += y;
	}
}
int ask(int x) {
	int sum = 0;
	for(; x > 0; x -= (x & -x)) {
		sum += c[x];
	}
	return sum;
}
int main() {
	cin >> n;
	vector<side> v;
	for(int i = 1; i <= n; i++) {
		cin >> m;
		for(int i = 0; i < m; i++) {
			cin >> xx[i] >> yy[i];
			xx[i]++; yy[i]++;
		}
		int p = 0;
		for(int i = 0; i < m; i++) {
			if(xx[i] == xx[p] && yy[i] < yy[p]) p = i;	//找到起始点,注意 y 轴也要判
			else if(xx[i] < xx[p]) p = i;
		}
		int val = 1;
		for(int i = 0; i < m; i++) {
			int w = (i + p) % m;
			tv[w] = val;	//给点加权
			val = -val;
		}
		for(int i = 0; i < m; i += 2) {	//判断
			if(yy[i] < yy[i + 1]) v.push_back({xx[i], yy[i], yy[i + 1], tv[i]});
			else v.push_back({xx[i], yy[i + 1], yy[i], tv[i + 1]});
		}
	}
	sort(v.begin(), v.end(), [](side x, side y) {	//按 x 排序
		if(x.x != y.x) return x.x < y.x;
		else return x.ya < y.ya;
	});
	v.push_back({M + 1, 1, 1, 0});	//避免结尾有点没判
	vector<query> que;
	cin >> q;
	for(int i = 1; i <= q; i++) {
		cin >> xx[i] >> yy[i];
		xx[i]++; yy[i]++;
		que.push_back({xx[i], yy[i], i});	//离线
	}
	sort(que.begin(), que.end(), [](query x, query y) {	//排序
		if(x.x != y.x) return x.x < y.x;
		else return x.y < y.y;
	});
	int pos = 0;
	for(auto it : v) {
		int x = it.x, ya = it.ya, yb = it.yb, val = it.val;
		for(; que[pos].x < x && pos < (int)que.size(); pos++) {
			ans[que[pos].p] = ask(que[pos].y);	//若已经操作完则更新
		}
		add(ya, val); add(yb, -val);	//加权
	}
	for(int i = 1; i <= q; i++) cout << ans[i] << '\n';
	return 0;
}

标签:val,int,题解,ABC211F,yy,++,xx,que,Rectilinear
From: https://www.cnblogs.com/2020luke/p/18113972

相关文章

  • [ABC211D] Number of Shortest paths 题解
    [ABC211D]NumberofShortestpaths题解思路解析题目其实说得很明白了,就是最短路计数。我们可以用一个\(s_i\)表示从起点到\(i\)的最短路计数,然后进行bfs,由于边权为\(1\),所以可以使用bfs求最短路。如果\(u\tov\)是\(v\)的最短路的其中一段,就把\(s_u\tos_v\)......
  • [ABC221D] Online games 题解
    [ABC221D]Onlinegames题解思路解析可以发现题目就是单纯区间加和查询每一个值有多少次出现。首先看到区间修改加结束时查询可以想到差分,但是通过\(A_i\le10^9\)发现值域很大没法直接根据值差分。于是想到离散化,将每个点离散下来,统计每两个离散的时间之间在线的人乘上时间......
  • [ABC223E] Placing Rectangles 题解
    [ABC223E]PlacingRectangles题解思路解析根据题目可知,其实三个长方形无非只有以下两种摆放方式。若大长方形长为\(y\),宽为\(x\),则我们对于第一种情况就固定住宽,判断能否使长度小于等于长;对于第二种情况同样固定住宽,此时A长方形右边空间的长就确定了,就只需要判断B,C......
  • [ABC221E] LEQ 题解
    [ABC221E]LEQ题解思路解析很有思维量的一道题。首先根据题目要求发现,新求的子序列只跟子序列的头尾有关,而在确定头尾之后中间的元素选或不选没有任何关系。也就是确定新子序列的头尾下标分别为\(i,j\),那么以当前头尾的可行子序列个数就是\(2^{j-i-1}=2^j\div2^{i+1}\)种......
  • 【阿里淘天笔试题汇总】2024-04-03-阿里淘天春招笔试题(第一套)-三语言题解(CPP/Pytho
    ......
  • 【阿里淘天笔试题汇总】2024-04-03-阿里淘天春招笔试题(第二套)-三语言题解(CPP/Pytho
    ......
  • Luogu P8710 [蓝桥杯 2020 省 AB1] 网络分析 题解 [ 绿 ] [ 带权并查集 ]
    原题分析本题由于从一个节点发信息,同一个集合内的所有点都会收到信息,显然是一道要求维护各节点间关系的题,因此采用并查集的数据结构进行求解。但由于维护关系的同时还要维护权值,所以采用带权并查集,它是一种能维护某个节点与其祖宗节点之间关系的数据结构。带权并查集找父亲的......
  • 大学教材《C语言程序设计》(浙大版)课后习题解析 | 第九、十章
    概述    本文主要提供《C语言程序设计》(浙大版)第九、十章的课后习题解析,以方便同学们完成题目后作为参考对照。后续将更新第十一、十二章节的课后习题解析,如想了解更多,请持续关注该专栏。专栏直达链接:《C语言程序设计》(浙大版)_孟俊宇-MJY的博客-CSDN博客​http://......
  • P10296 [CCC 2024 S2] Heavy-Light Composition 题解
    思路先扫一遍,计算每个字母出现的数量,然后判断是否是交替出现。代码#include<bits/stdc++.h>usingnamespacestd;intmain(){ intT,n; cin>>T>>n; while(T--){ intt[105]={0}; strings; cin>>s; for(inti=0;i<n;i++)t[s[i]-'a&#......
  • CF1909G Pumping Lemma 题解
    题目链接题目要求我们对合法三元组进行计数,直接做是困难的,因此考虑通过枚举确定一部分元素再进行判定求解,那我们固定什么呢?固定\(x\)和\(y+z\)的分界线没啥用,因此我们枚举确定\(S\)中\(x+y\)和\(z\)的分界线,这样能确定一长串\(y^{k-1}\)所在的区间。接着我们不难想......