首页 > 其他分享 >【DSY】直线 题解(平面分块)

【DSY】直线 题解(平面分块)

时间:2022-12-05 23:55:44浏览次数:60  
标签:return yl 分块 int 题解 DSY dep yr mx

Link.

平面分块

Solution

直接观察题面可以发现,这道题实在没有什么高深的技巧性可言。

于是我们直接暴力:分块。

然后 wjy 大佬表示,这个做法有着二维线段树的思想。

下面阐述一下平面分块。

其实就是对于每个平面,将它直接划分为“田”字型等面积的四个子平面,类似线段树,不断剖分下去,然后固定一个深度。对于一个平面 \(t_o\),如果当前输入的直线 \(i\) 有可能穿过这个平面,那就把 \(i\) 压入 \(t_o\) 的 vector 里。查询的时候,类线段树查询,找到这个点所在的、最小的子平面,然后依次枚举即可。

在判断“该直线是否会穿过该节点”时,会涉及到一个三个点两两斜率的比较,这个斜率 dp 的实现也涉及到了,转为乘法即可。

最后,这个复杂度级别估着不大,可过。

Code

#include<bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i <= b; ++i)
const int maxn = 1e5 + 5, maxd = 7, inf = 1e9;
int n, q, nw, tot = 1;
double nk, nb;
int X1[maxn], X2[maxn], Y1[maxn], Y2[maxn];
struct node{
	int c[2][2]; vector <int> d;
}t[maxn << 3];
int fx[4][2] = {{1, 0}, {0, 1}, {0, 0}, {1, 1}};

inline void build(int o, int dep, int xl, int xr, int yl, int yr){
	double ny1 = xl * nk + nb, ny2 = xr * nk + nb;
	if((ny1 > yr and ny2 > yr) or (ny1 < yl and ny2 < yl)) return;
	t[o].d.push_back(nw); 
	if(dep == maxd) return;
	rep(i, 0, 3) if(!(t[o].c[fx[i][0]][fx[i][1]])) 
		t[o].c[fx[i][0]][fx[i][1]] = ++tot; 
	int mx = (xl + xr) >> 1, my = (yl + yr) >> 1;
	build(t[o].c[0][0], dep + 1, xl, mx, yl, my), build(t[o].c[0][1], dep + 1, xl, mx, my + 1, yr);
	build(t[o].c[1][0], dep + 1, mx + 1, xr, yl, my), build(t[o].c[1][1], dep + 1, mx + 1, xr, my + 1, yr);
}
inline int qry(int i, int dep, int xl, int xr, int yl, int yr, int x, int y){
	if(!i) return 0;
	if(dep == maxd){ int res = 0;
		for(auto dk : t[i].d) 
			if(1ll * (Y1[dk] - Y2[dk]) * (X1[dk] - x) == 1ll * (Y1[dk] - y) * (X1[dk] - X2[dk])) res += 1;
		return res;
	} int mx = (xl + xr) >> 1, my = (yl + yr) >> 1;
	if(x <= mx and y <= my) return qry(t[i].c[0][0], dep + 1, xl, mx, yl, my, x, y);
	else if(x <= mx) return qry(t[i].c[0][1], dep + 1, xl, mx, my + 1, yr, x, y);
	if(x > mx and y <= my) return qry(t[i].c[1][0], dep + 1, mx + 1, xr, yl, my, x, y);
	else if(x > mx) return qry(t[i].c[1][1], dep + 1, mx + 1, xr, my + 1, yr, x, y);
	return 0;
}

int main(){
	scanf("%d%d", &n, &q);
	rep(i, 1, n){ 
		scanf("%d%d%d%d", &X1[i], &Y1[i], &X2[i], &Y2[i]);
		nk = (double)(Y1[i] - Y2[i]) / (X1[i] - X2[i]), nb = Y1[i] - nk * X1[i], nw = i;
		build(1, 1, 1, inf, 1, inf);
	} while(q--){ int x, y;
		scanf("%d%d", &x, &y);
		printf("%d\n", qry(1, 1, 1, inf, 1, inf, x, y));
	} return 0;
}

RP++;

标签:return,yl,分块,int,题解,DSY,dep,yr,mx
From: https://www.cnblogs.com/gsn531/p/16953951.html

相关文章

  • 服务器consul与本地服务健康检查不通问题解决
    (125条消息)服务器consul与本地服务健康检查不通问题解决_向往鸟的博客-CSDN博客_consul健康检查失败 云服务猿如意 搜索--......
  • 【题解】The 2022 ICPC Asia Hangzhou Regional Programming Contest (第 47 届 ICPC
    D.MoneyGame一开始有\(n\)个人围成一圈,第\(i\)个人手上有\(a_i\)的存款(实数),每一轮从第一个人开始,每个人把自己手上的一半存款给下一个人,问稳定时每个人手上存款......
  • 零钱兑换问题——三种题解方法
    第一种:暴力解法:5、2、1都考虑,只有等于才可cnt++,小于m要continue,大于m要break#include<iostream>usingnamespacestd;intmain(){intm,cnt=0;cin>>m......
  • 题解 [AGC047C] Product Modulo
    显然不能暴力算两两的乘积,而积取模而结果不取模提示我们模数肯定有用。所有为\(0\)的\(a_i\)对答案不会产生任何贡献,可以直接删除,下文不再考虑这种情况。同时我们约定......
  • 能力提升——搜索 题解
    BP5194[USACO05DEC]ScalesS在洛谷,享受coding的快乐AC历程:0pts(MLE)60pts(6AC+4TLE)100pts(AC)虽然题目中说n≤1000,但考虑到“每个砝码的质量至少等于前面两个......
  • JOISC 2022 简要题解
    版刷JOISC的计划就这么结束了。鸽了许多题,懵懵懂懂过来的,兴奋的开始,中途得知省选没了,又鸽了一段时间。好歹是完结了,撒花撒花。总体上题目质量很高,很开心以及荣幸有机会......
  • 题解 [ARC121D] 1 or 2
    诈骗题,竟然评到了\(2784\)的惊人高分(快到红了),来补个题解。题意:有两个可重集\(A,B\),\(B\)初始为\(\varnothing\)。每次从\(A\)中删除一个或两个数,并将它们的和加入......
  • 无知时诋毁原神——题解
    P8880无知时诋毁原神题意简述:给定一个\(0\simn-1\)的排列\(c\)。构造两个同样为\(0\simn-1\)的排列的\(a,b\),满足\(\foralli\in[1,n],c_i=(a_i+b_i)\bmodn\)。如......
  • sql题解--打折日期交叉问题
    题目-打折日期交叉问题现有各品牌优惠周期表(promotion_info)如下,其记录了每个品牌的每个优惠活动的周期,其中同一品牌的不同优惠活动的周期可能会有交叉。promotion_id......
  • win11系统vmware虚拟机报错“不支持嵌套虚拟化”问题解决方案汇总
    一、报错内容vmware0虚拟机中开启虚拟化主机时,报错“Error:Failureinvalidatingvirtualizationcapabilities”[root@localhost~]#rht-vmctlfullresetclassroom......