首页 > 其他分享 >P4169 题解

P4169 题解

时间:2023-08-04 16:34:13浏览次数:28  
标签:ch return Point int 题解 void mid P4169

题意

二维平面上有 \(n\) 个点,给你 \(m\) 次操作,每次操作可以插入一个点或者询问所有点中距离给定点最近的哈密顿距离。\(n,m\le 3\times 10^5.\)

分析

这是一道 K-D Tree 的裸题。

而对于这道题,我们还需要考虑插入操作。我们给出两种方式:

  1. 按很多题解的思路,在这棵树上直接按普通二叉树的插入方式一维一维地递归下去,找到一个空节点就插入。不过有可能导致整棵树不平衡,而这种二叉树又不能像平衡树一样旋来旋去(否则就不符合左右儿子与父节点的坐标关系),所以只能用最朴素的替罪羊树的思想:要么定期重构,要么插入时检查这个子树是否不平衡,不平衡就重构整棵子树。重构方式是先还原成原来这棵子树中的点的序列(拍扁),再按建树方式重构;不平衡率 \(\alpha\) 一般设为 \(0.75\) 左右。
  2. 其实上面的做法有点 naive,因为它需要重构,而重构的复杂度很高,代码又很长。所以我们想一种不用重构的方法:首先离线,把原来 \(n\) 个点和所有需要插入的点全部记录下来,然后对于每个点记录一个删除标记 del,原来需要插入的点删除标记为 \(1\)。然后对所有记录下来的点来建成一棵 K-D Tree。这样原来的插入操作变成了单点修改删除标记!而且还不用写重构,复杂度也很低。至于查询,只用更新没有删除的点即可。

对于方式 2,假设一个点被删除,那记录最左端、最下端为 inf,最右端、最上端为 -inf,然后按正常方式从左右儿子更新即可。

直接一发最优解!(2023.2.13 12:00)

代码

这里给出方法 2 代码:

#include <bits/stdc++.h>
using namespace std;
#define gc getchar
#define pc putchar
typedef double db;
inline int read() {
	int x = 0; char ch = gc();
	while (!isdigit(ch)) ch = gc();
	while (isdigit(ch))
		x = x * 10 + ch - 48, ch = gc();
	return x;
}
inline void write(int x) {
	if (!x) return (void)(pc('0'), pc('\n'));
	char ch[50]; int tp = 0;
	while (x) ch[++tp] = x % 10 + 48, x /= 10;
	while (tp) { pc(ch[tp--]); } pc('\n');
} const int N = 600010, inf = 0x3f3f3f3f;
inline db sqr(db x) { return x * x; }
inline void chkmn(int &x, int y) { x = min(x, y); }
inline void chkmx(int &x, int y) { x = max(x, y); }
struct Query { int x, y; } q[N];
struct Point { int x, y, del, rev; } a[N];
int n, m, ans, cnt, root, lc[N], rc[N], d[N];
int L[N], R[N], D[N], U[N];
int id[N];
inline void push_upi(int x, int o) {
	chkmn(L[x], L[o]), chkmn(D[x], D[o]);
	chkmx(R[x], R[o]), chkmx(U[x], U[o]);
}
inline void push_up(int x) {
	if (!a[x].del) 
		L[x] = R[x] = a[x].x, D[x] = U[x] = a[x].y;
	else L[x] = D[x] = inf, R[x] = U[x] = -1;
	if (lc[x]) push_upi(x, lc[x]);
	if (rc[x]) push_upi(x, rc[x]);
}
int build(int l, int r) {
	if (l > r) return 0;
	int mid = (l + r) >> 1;
	db avx = 0, avy = 0, sx = 0, sy = 0;
	for (int i = l; i <= r; i++)
		avx += a[i].x, avy += a[i].y;
	avx /= (r - l + 1), avy /= (r - l + 1);
	for (int i = l; i <= r; i++)
		sx += sqr(a[i].x - avx),
		sy += sqr(a[i].y - avy);
//	按方差划分维度
	if (sx > sy)
		nth_element(a + l, a + mid, a + r + 1,
			[&](const Point& u, const Point& v) {
				return u.x < v.x; }), d[mid] = 1;
	else nth_element(a + l, a + mid, a + r + 1,
			[&](const Point& u, const Point& v) {
				return u.y < v.y; }), d[mid] = 2;
	id[a[mid].rev] = mid; // 记录每个点在树上的编号,方便修改
	lc[mid] = build(l, mid - 1);
	rc[mid] = build(mid + 1, r);
	push_up(mid);
	return mid;
}
void update(int l, int r, int x) {
	int mid = (l + r) >> 1;
	if (x == mid)
		return (void)(a[x].del = 0, push_up(x));
	if (x < mid) update(l, mid - 1, x);
	else update(mid + 1, r, x);
	push_up(mid);
}
Point k;
inline int dis(Point u, Point v) {
	return abs(u.x - v.x) + abs(u.y - v.y);
}
inline int mndis(int u, Point v) {
//	这个点到矩形的最小距离
	if (!u) return inf;
	int res = 0;
	if (v.x < L[u]) res += L[u] - v.x;
	if (v.x > R[u]) res += v.x - R[u];
	if (v.y < D[u]) res += D[u] - v.y;
	if (v.y > U[u]) res += v.y - U[u];
	return res;
}
void query(int x) {
//	更新每个可能会被更新的点
	if (!a[x].del) chkmn(ans, dis(a[x], k));
	int dl = mndis(lc[x], k), dr = mndis(rc[x], k);
	if (dl < ans && dr < ans) {
		if (dl < dr) {
			query(lc[x]);
			if (dr < ans) query(rc[x]);
		} else {
			query(rc[x]);
			if (dl < ans) query(lc[x]);
		}
	} else {
		if (dl < ans) query(lc[x]);
		if (dr < ans) query(rc[x]);
	}
}
int T[N];
int main() {
	n = read(), m = read(), cnt = n;
	for (int i = 1; i <= n; i++) 
		a[i].x = read(), a[i].y = read(), a[i].rev = i;
	for (int i = 1; i <= m; i++) {
		int t = read(), x = read(), y = read();
		if (t == 1) 
        a[++cnt] = (Point){x, y, 1, cnt};
		else q[i] = (Query){x, y};
		T[i] = t;
	}
	root = build(1, cnt);
	for (int i = 1, now = n; i <= m; i++) 
		if (T[i] == 1) update(1, cnt, id[++now]);
		else {
			ans = inf, k = (Point){q[i].x, q[i].y};
			query(root);
			write(ans);
		}
	return 0;
}

标签:ch,return,Point,int,题解,void,mid,P4169
From: https://www.cnblogs.com/laijinyi/p/17606349.html

相关文章

  • AT_ttpc2015_g 题解
    洛谷的RMJ总是UKE,所以这一题是在ATcoder上做的,记录一,记录二。思路一首先字符串长度一定是\(6\)的倍数,然后判断是否只有\(t\)、\(i\)、\(e\)、\(c\)、\(h\)这五个字符,最后统计一下字符个数就行了。代码(错误):#include<iostream>#include<string>usingnamespacestd;......
  • UVA333 题解
    ##大意:给定一个字符串$s$判断$s$是否符合要求。1.由数字,`-`和大写英文数字`X`,空格组成,`X`代表$10$且只能在最后出现。2.依次相加前面的数字的总和可以被$11$整除,也就是前缀和,而且刚好$s$只有$10$个数字。---##坑点:1.`\r`换行与空格。你写完代码在洛谷......
  • Python爬虫遇到重定向问题解决办法汇总
    在进行Python爬虫任务时,遇到重定向问题是常见的问题之一。重定向是指在发送请求时,服务器会返回一个新的URL,将请求重新定向到该URL。为了帮助您解决这个问题,本文将提供一些实用的解决办法,并给出相关的代码示例,希望能对您的爬虫任务有所帮助。了解重定向问题重定向问题通常是由于网......
  • T1的题解
    一道小清新的思维题!和\(bocchi\)酱一样可爱的喵30pts首先典中典套路:破环成链,数组复制一份。设\(to[i]=\max(\mathbbj)(j\geqi\wedge\sum_{i\leql\leqj}a_l\leqk)\)枚举起始下标,容易想到贪心,考虑前\(i\)个已经确定好怎样分段了,下一个段一定是\([i,to[i]]......
  • P4826 [USACO15FEB] Superbull S题解
    SuperbullS题解题目传送门(可点击)题面题目描述\(Bessie\)和她的朋友们正在一年一度的\(Superbull\)锦标赛中打球,而\(Farmer\)\(John\)负责让比赛尽可能激动人心。总共有N支队伍(\(1\leN\le2000\))参加了\(Superbull\)锦标赛。每个团队都有一个\(1...2^{30}−1\)的团队ID......
  • java 同一个对象之间赋值后添加入List中,属性值相互覆盖的问题解决方案
    1、for循环中NEW对象,因为List中存的是对象的引用地址。2、BeanUtils是属于spring框架下beans包下的工具类BeanUtils它提供了对java反射和自省API的包装。它里面还有很多工具类,这篇文章我们介绍一下copyProperties这个方法使用情景一般当我们有两个具有很多相同属性的JavaBean......
  • RTSP流媒体服务器LntonNVR(源码版)平台前端打包出现“UglifyJsPlugin”报错的问题解决
    LntonNVR既有软件版也有硬件版,平台基于RTSP/Onvif协议将前端设备接入,可实现的视频能力有视频监控直播、录像、视频转码分发、检索与回放、云存储、智能告警、国标级联等。平台可将接入的视频流进行转码分发,对外输出的视频流格式包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等。......
  • 国标GB28181平台LntonGBS(源码版)国标视频平台在连接MySQL数据库时提示“can’t connect
    LntonGBS国标视频云服务平台不仅支持无缝、完整接入内网或者公网的国标设备,还能够实现全平台、全终端输出。该平台支持将GB/T28181的设备/平台推送的PS流转成ES流,并提供RTSP、RTMP、FLV、HLS、WebRTC等多种格式视频流的分发服务,实现Web浏览器、手机浏览器、微信端、PC客户端等各终......
  • 【csp2020】 方格取数 题解
    洛谷传送门1.题目大意给定一个\(n*m\)的矩阵,矩阵中每个点\((i,j)\)都有一个权值\(f_{(i,j)}\)。每次可以向上,向下或向右走。问从\((1,1)\)走到\((n,m)\),经过的路径上点的权值之和最大是多少?2.思路这道题我们不难想到动态规划。但是与一般的动规不同的是,本题中有上下右......
  • 【题解】Luogu[P5022] [NOIP2018 提高组] 旅行
    Link因为是道NOIP,那么我们不妨按照考场上的策略一点一点想。先看部分分,有一档有很明显的特征\(n=m-1\)这显然构成一棵树,对于一棵树,我们想把他按照题目的要求遍历完,一定是像dfs的遍历顺序一样,对于一个点,必然遍历完以它为根的子树,才能回到它的父亲节点,于是就有了一个很明显的贪......