首页 > 其他分享 >重学OI #3 DS特别篇

重学OI #3 DS特别篇

时间:2023-10-16 13:57:44浏览次数:44  
标签:rt 重学 特别篇 int 复杂度 mid kdt 矩形 DS

这一篇和前两篇目的不太一样,这里更加偏向于一些好玩的神奇科技

part1 K-D tree

众所周知ben喜欢分块,但是分块不能(难以)处理多维问题

ben不喜欢树套树,但是树套树可以

所以ben决定学 KDT从而减少学树套树(

kdt最大的优势在于对脑子需求小,只需要你能码

首先我们考虑kdt是什么

它是一棵二叉排序树,每一个节点管辖一个(超)矩形,什么叫超矩形?就是高维的"矩形"

构造

说的俗气一点,就是建树。我们希望这棵树尽可能在根号以下复杂度完成正常操作(否则跑不跑得过暴力都不好说)

参考平衡树,我们希望树高在对数级别

首先,我们需要保证,节点 \(u\) 的儿子所管辖的所有点都在 \(u\) 管辖矩形内

通常我们应对的都是二维三维问题,以二维为例

需要满足要求,最好的办法就是用一条横平竖直的线分割 \(u\) 的矩形,分别分给左右儿子

具体构造如下:

  • 挑选一个维度,选择与该维度正交的超平面分割当前区域。对于二维就是一线分面

  • 不妨假设若干点中,我们正在对其 \(x\) 作为标准划分。处于均匀的目的,不妨选择以点的 \(x\) 坐标中位数作为标准

  • 继续分治下去,选择不同维度

其实是非常类似于划分树的

不妨考虑如何决定分割维度

两种做法是:

  • 轮换分割:比如先 \(x\) 后 \(y\) 再 \(z\)

  • 方差划分:哪一维方差大按哪一维

本文全程使用轮换因为好写,实际据说方差快一些,但是反正骗分干嘛写难写的啊

寻找中位数使用 nth_element 可以线性,可以算出总复杂度nlong,满足我们需求:

区间查询问题(RQ)

类似于线段树的思想,查询一个矩形 \(R\) 可以分为三类点:

  1. 无交,自然与答案无关

  2. 被包含,自然直接计入答案结束

  3. 部分交集

显然我们类似于线段树,一直经过第三类点,然后到12类为止

并且我们可以考虑到12类的子树内肯定不会有3类点,所以复杂度直接和3类点数量有关

对于每个矩形的边,考虑其穿过的节点个数

处于轮换,相邻两次必定是分别划分 \(x,y\)

从点数上来说,划分出的四个区域中每个'大小' 都是原先四分之一

设 \(T(n)\) 为大小为 \(n\) 的kdt中过区域数,则 \(T(n)=2T(n/4)+O(1)=O(\sqrt n)\)

复杂度得以保障

一个细节地方在于,由于划分的矩形在边界是有交的,所以一条直线可能经过了超过两个节点,那我们的分析就是错误的...吗?

实际上,递归向儿子,线总在一侧,不影响复杂度分析

值得一提,在 \(k\) 维空间里经过个数是 \(O(n^{1-\frac{1}{k}})\)

具体举个例子:Shooting Gallery

原先题意中给出的用射击点匹配矩形(靶子)很不聪明,难以实现

反过来考虑,让每个矩形去匹配自己对应射击点

先按高度排个序

对于射击点建立一棵 kdt,维护子树编号最小未被匹配而删除的射击点,RQ之后单点删除被匹配点即可

给出实现:

#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1600005;
#define ls (rt<<1)
#define rs (rt<<1|1)
struct node{
    int xl,yl,xr,yr,p;
}a[N<<2];

struct point{
    int x,y,p;
}p[N];

struct squ{
    int xl,xr,yl,yr,p,h;
}s[N];

int m;

bool cx(point A,point B){return A.x<B.x;}
bool cy(point A,point B){return A.y<B.y;}
bool yzy(squ A,squ B){
    return A.h<B.h;
}

int ans[N];

void pushup(int rt){
    a[rt].p=min(a[ls].p,a[rs].p);
    a[rt].xl=min(a[ls].xl,a[rs].xl);
    a[rt].yl=min(a[ls].yl,a[rs].yl);
    a[rt].xr=max(a[ls].xr,a[rs].xr);
    a[rt].yr=max(a[ls].yr,a[rs].yr);
}

void build(int l,int r,int rt,bool D){
    if(l==r){
        a[rt].xl=a[rt].xr=p[l].x;
        a[rt].yl=a[rt].yr=p[l].y;
        a[rt].p=p[l].p;
        return ;
    }
    int mid=(l+r)>>1;
    nth_element(p+l,p+mid,p+r+1,D?cx:cy);
    build(l,mid,ls,!D);
    build(mid+1,r,rs,!D);
    pushup(rt);
}
int to;
void upd(int l=1,int r=n,int rt=1){
    if(l==r){
        a[rt].p=n+1;return;
    }
    int mid=(l+r)>>1;
    if(to<=mid) upd(l,mid,ls);
    else upd(mid+1,r,rs);
    a[rt].p=min(a[ls].p,a[rs].p);
}

node wt;
int tp[N];

void query(int rt=1){
    if(a[rt].p>=wt.p or wt.xr<a[rt].xl or a[rt].xr<wt.xl or wt.yr<a[rt].yl or wt.yl>a[rt].yr){
        return;
    }
    if(wt.xl<=a[rt].xl and a[rt].xr<=wt.xr and wt.yl<=a[rt].yl and a[rt].yr<=wt.yr){
        wt.p=min(wt.p,a[rt].p);
        return;
    }
    if(a[ls].p<a[rs].p){
        query(ls),query(rs);
    }
    else query(rs),query(ls);
}

int main(){
    cin>>m;
    for(int i=1;i<=m;i++){
        cin>>s[i].xl>>s[i].xr>>s[i].yl>>s[i].yr>>s[i].h;
        s[i].p=i;
    }
    sort(s+1,s+m+1,yzy);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>p[i].x>>p[i].y;p[i].p=i;
    }
    build(1,n,1,1);
    for(int i=1;i<=n;i++) tp[p[i].p]=i;
    for(int i=1;i<=m;i++){
        wt=(node){s[i].xl,s[i].yl,s[i].xr,s[i].yr,n+1};
        query();
        if(wt.p==n+1) continue;//cout<<i<<endl;
        ans[wt.p]=s[i].p;
        to=tp[wt.p];
        upd();
    }
    for(int i=1;i<=n;i++) cout<<ans[i]<<"\n";
}

part2 珂朵莉树(ODT)

to be upd

标签:rt,重学,特别篇,int,复杂度,mid,kdt,矩形,DS
From: https://www.cnblogs.com/exut/p/17739912.html

相关文章

  • 教你如何基于MindSpore进行ChatGLM微调
    本文分享自华为云社区《基于MindSpore的ChatGLM微调》,作者:JeffDing。基于MindSpore的ChatGLM微调克隆HuggingFace模型克隆chatglm-6b代码仓,下载分布式的模型文件gitlfsinstallgitclonehttps://huggingface.co/THUDM/chatglm-6b准备环境安装Transformerpipinsta......
  • #yyds干货盘点# LeetCode程序员面试金典:H 指数
    题目:给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。根据维基百科上 h指数的定义:h 代表“高引用次数”,一名科研人员的 h 指数 是指他(她)至少发表了 h 篇论文,并且每篇论文 至少 被引用 h 次......
  • #yyds干货盘点# LeetCode程序员面试金典:四数相加 II
    1.简述:给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i,j,k,l) 能满足:0<=i,j,k,l<nnums1[i]+nums2[j]+nums3[k]+nums4[l]==0 示例1:输入:nums1=[1,2],nums2=[-2,-1],nums3=[-1,2],nums4=[0,2]输出:2......
  • Landsat 8 Collection 2 Tier 1 calibrated top-of-atmosphere (TOA) reflectance
    Landsat8Collection2Tier1calibratedtop-of-atmosphere(TOA)reflectance.Calibrationcoefficientsareextractedfromtheimagemetadata.See Chanderetal.(2009) fordetailsontheTOAcomputation.Landsatsceneswiththehighestavailabledataqual......
  • MySQL错误:check the manual that corresponds to your MySQL server version for the
    在MySQL执行以下SQL报错DELIMITER//CREATEPROCEDUREgenerate_and_insert_data()BEGINDECLAREiINTDEFAULT1;DECLAREjINTDEFAULT1;DECLAREtotal_iterationsINTDEFAULT1000;WHILEi<=total_iterationsDO--创建临时表用于存储生成......
  • #yyds干货盘点# LeetCode程序员面试金典:整数转换英文表示
    题目:将非负整数 num 转换为其对应的英文表示。 示例1:输入:num=123输出:"OneHundredTwentyThree"示例2:输入:num=12345输出:"TwelveThousandThreeHundredFortyFive"示例3:输入:num=1234567输出:"OneMillionTwoHundredThirtyFourThousandFiveHundredSixtySe......
  • #yyds干货盘点# LeetCode程序员面试金典:最小操作次数使数组元素相等
    1.简述:给你一个长度为 n 的整数数组,每次操作将会使 n-1 个元素增加 1 。返回让数组所有元素相等的最小操作次数。 示例1:输入:nums=[1,2,3]输出:3解释:只需要3次操作(注意每次操作会增加两个元素的值):[1,2,3]=>[2,3,3]=>[3,4,3]=>[4,4,4]示例2:输入:nums=[1......
  • #yyds干货盘点#Electron 主进程和渲染进程
    本节我们来学习什么是主进程和渲染进程,主进程与渲染进程之间有什么区别,主进程和渲染进程之间的通信。下面我们先来看一下进程的概念。进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。什么是主进程在 Electro......
  • 3DS MAX 2024中文版 下载及安装教程
    软件介绍:3DStudioMax,常简称为3dMax或3dsMAX,是Discreet公司开发的(后被Autodesk公司合并)基于PC系统的3D建模渲染和制作软件。其前身是基于DOS操作系统的3DStudio系列软件。在WindowsNT出现以前,工业级的CG制作被SGI图形工作站所垄断。 安装和使用教程:1.通过文章末尾处下载软件......
  • # yyds干货盘点 # Pandas将三个聚合结果的列,如何合并到一张表里?
    大家好,我是皮皮。一、前言前几天在Python最强王者交流群【斌】问了一个Pandas数据处理的问题,一起来看看吧。求教:将三个聚合结果的列,如何合并到一张表里?这是前两列,能够合并。这是第三列,加权平均,也算出来了。但我不会合并。。。。二、实现过程后来【隔壁......