[luogu3380][bzoj3196]【模板】二逼平衡树【树套树】

题目地址

【洛谷传送门】

题目大意

区间查询k的排名,查找k排名的数,单点修改,区间前驱,区间后继。

感想

真的第一次写树套树,整个人都不对了。重构代码2次,发现样例都过不了,splay直接爆炸,可能是我太弱了。
换了treap,就过掉了。
但是理解树套树的思路也花了我不少的时间。

分析

很多人都不知道树套树是什么东西,我一开始也是很懵逼的。
为什么两棵树可以套在一起??这是什么操作??
但是HG的xyc大佬给我点波了一句话,我就明白了。
因为原来的线段树中只有tag一个标记,我们记录的东西就太少了。也不方便操作,那么我们就将这个线段树的所有节点都换成一棵平衡树就可以了。
如果有时间我一定会写一个树套树的详细总结(flag)。
但是我们不是对每一个节点都建一个关于整体的平衡树的节点,这样复杂度太高了,我们就将这个区间内的所有点都扔到一个平衡树中,是不是非常暴力呢??
其实这样的做法,仅仅增加了空间复杂度\(log_2n \times n\)的空间,因为我们需要建多棵平衡树,所以我们一开始就准备一大堆的空节点,如果有需要的,那么就直接从空节点中拿一个就可以了,
那么关于时间复杂度,其实也就只是增加了一个平衡树的单次操作的\(log\)
但是有一个例外,就是操作2。
因为我们需要查找排名k的数,那么我们选择二分答案,每一次枚举rank,然后检验是否在k内,那么操作2还需要一个log的复杂度,所以差不多就是\(log_n^3 \times n\)的复杂度。

代码

#include <bits/stdc++.h>
#define inf 2147483647
#define lc (nod << 1)
#define rc (nod << 1 | 1)
#define N 500004
using namespace std;
template <typename T>
inline void read(T &x) {x = 0; T fl = 1;char ch = 0;while (ch < '0' || ch > '9') {if (ch == '-') fl = -1;ch = getchar();}while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}x *= fl;
}
struct node {int val, cnt, ch[2], sz, rd;void init(int x) {val = x; cnt = sz = 1; ch[1] = ch[0] = 0; rd = rand() % 100;}
}tr[N * 20];
int tot;
struct Treap {#define ls tr[nod].ch[0]#define rs tr[nod].ch[1]void pushup(int nod) {tr[nod].sz = tr[ls].sz + tr[rs].sz + tr[nod].cnt;}void rotate(int &nod, int d) {int k = tr[nod].ch[d];tr[nod].ch[d] = tr[k].ch[d ^ 1];tr[k].ch[d ^ 1] = nod;pushup(nod); pushup(k);nod = k;}void ins(int &nod, int val) {if (!nod) {tr[nod = ++ tot].init(val);return;}tr[nod].sz ++;if (tr[nod].val == val) {tr[nod].cnt ++;return;}int d = val > tr[nod].val;ins(tr[nod].ch[d], val);if (tr[nod].rd > tr[tr[nod].ch[d]].rd) rotate(nod, d);}void del(int &nod, int val) {if (!nod) return;if (tr[nod].val == val) {if (tr[nod].cnt > 1) {tr[nod].cnt --;tr[nod].sz --;return;}int d = tr[ls].rd > tr[rs].rd;if (ls == 0 || rs == 0) nod = ls + rs;else rotate(nod, d), del(nod, val);}else tr[nod].sz --, del(tr[nod].ch[tr[nod].val < val], val);}int rk(int nod, int val) {if (!nod) return 0;if (tr[nod].val == val) return tr[ls].sz;if (tr[nod].val > val) return rk(ls, val);else return tr[ls].sz + tr[nod].cnt + rk(rs, val);}int kth(int nod, int k)  {while (233) {if (k <= tr[ls].sz) nod = ls;else if (k > tr[ls].sz + tr[nod].cnt) k -= tr[ls].sz + tr[nod].cnt, nod = rs;else return tr[nod].val;}}int pre(int nod, int val) {if (!nod) return -inf;if (tr[nod].val >= val) return pre(ls, val);else return max(tr[nod].val, pre(rs, val));}int suc(int nod, int val) {if (!nod) return inf;if (tr[nod].val <= val) return suc(rs, val);else return min(tr[nod].val, suc(ls, val));}
}tp[N << 2];
int n, m;
int a[N], rt[N];
void build(int nod, int l, int r) {for (int i = l; i <= r; i ++) tp[nod].ins(rt[nod], a[i]);if (l == r) return;int mid = (l + r) >> 1;build(lc, l, mid);build(rc, mid + 1, r);
}
int query_rk(int nod, int l, int r, int ql, int qr, int k) {if (l > qr || r < ql) return 0;if (ql <= l && r <= qr) return tp[nod].rk(rt[nod], k);int mid = (l + r) >> 1, res = 0;res += query_rk(lc, l, mid, ql, qr, k);res += query_rk(rc, mid + 1, r, ql, qr, k);return res;
}
void update_point(int nod, int l, int r, int k, int val) {if (k < l || k > r) return;tp[nod].del(rt[nod], a[k]);tp[nod].ins(rt[nod], val);if (l == r) return;int mid = (l + r) >> 1;update_point(lc, l, mid, k, val);update_point(rc, mid + 1, r, k, val);
}
int query_pre(int nod, int l, int r, int ql, int qr, int k) {if (l > qr || r < ql) return -inf;if (ql <= l && r <= qr) return tp[nod].pre(rt[nod], k);int mid = (l + r) >> 1, res = query_pre(lc, l, mid, ql, qr, k);res = max(res, query_pre(rc, mid + 1, r, ql, qr, k));return res;
}
int query_suc(int nod, int l, int r, int ql, int qr, int k) {if (l > qr || r < ql) return inf;if (ql <= l && r <= qr) return tp[nod].suc(rt[nod], k);int mid = (l + r) >> 1, res = query_suc(lc, l, mid, ql, qr, k);res = min(res, query_suc(rc, mid + 1, r, ql, qr, k));return res;
}
int query_fd(int ql, int qr, int k) {int l = 0, r = 1e8, res = -1;while (l <= r) {int mid = (l + r) >> 1;if (query_rk(1, 1, n, ql, qr, mid) + 1 <= k) res = mid, l = mid + 1;else r = mid - 1;}return res;
}
int main() {srand(time(NULL));tot = 0;read(n); read(m);for (int i = 1; i <= n; i ++) read(a[i]);build(1, 1, n);for (int i = 1; i <= m; i ++) {int opt, x, y, z;read(opt);if (opt == 1) {read(x); read(y); read(z);printf("%d\n", query_rk(1, 1, n, x, y, z) + 1); }if (opt == 2) {read(x); read(y); read(z);printf("%d\n", query_fd(x, y, z));}if (opt == 3) {read(x); read(y);update_point(1, 1, n, x, y);a[x] = y;}if (opt == 4) {read(x); read(y); read(z);int res = query_pre(1, 1, n, x, y, z);printf("%d\n", res);}if (opt == 5) {read(x); read(y); read(z);int res = query_suc(1, 1, n, x, y, z);printf("%d\n", res);}}return 0;
}

转载于:https://www.cnblogs.com/chhokmah/p/10611369.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463011.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Parquet格式描述

背景 2010年 google 发表了一篇论文《Dremel: Interactive Analysis of Web-Scale Datasets》&#xff0c;介绍了其 Dermel 系统是如何利用列式存储管理嵌套数据的&#xff0c;嵌套数据就是层次数据&#xff0c;如定义一个班级&#xff0c;班级由同学组成&#xff0c;同学的信…

Notepad++ 快捷键 大全

修改快捷键的话&#xff1a;设置----管理快捷键----就好比第一个快捷键新建吧--------鼠标双击&#xff0c;然后会弹出来对话框让你对具体想要设置的快捷键进行设置&#xff0c;所有的快捷键都是这么设置的&#xff0c;但是我就是不明白&#xff0c;你要设置的是哪个&#xff1…

Kevin专栏---如何制作试用版安装包

首先需要在http://activationservice.installshield.com/doLogin.do注册一个试用账号。注册完成后系统会自动发送一个15天的试用账号和密码。 在图标Trialware Files上点击鼠标右键&#xff0c;创建一个试用配置项&#xff08;见下图&#xff09;。 首先选择试用文件&#xff0…

ldd命令解析

在linux中&#xff0c;经常会碰到查看可执行文件需要依赖哪些动态链接库&#xff0c;这时ldd命令就可以排上用场了 由于某种原因&#xff0c;屏蔽了一些内容&#xff0c;结果如下&#xff1a; 可以根据结果查找对应的动态链接库

UDP和TCP协议包大小的计算-转

UDP和TCP协议包大小的计算 UDP一次发送数据包的大小&#xff0c;TCP一次发送数据包的大小。MTU最大传输单元&#xff0c;这个最大传输单元实际上和链路层协议有着密切的关系&#xff0c;EthernetII帧的结构DMACSMACTypeDataCRC由于以太网传输电气方面的限制&#xff0c;每个以太…

洛谷 - P1361 - 小M的作物 - 最小割 - 最大权闭合子图

第一次做最小割&#xff0c;不是很理解。 https://www.luogu.org/problemnew/show/P1361 要把东西分进两类里&#xff0c;好像可以应用最小割的模板&#xff0c;其中一类A作为源点&#xff0c;另一类B作为汇点&#xff0c;价值就是边的容量。 然后最小割一定会割断每个中间结点…

LVS

1、安装lvs 在分发器上在172.16.10.1上执行&#xff0c;事先应该配置好你的yum源&#xff0c;保证能够读取介质中的Cluster目录&#xff01;&#xff03;yum install ipvsadm编写&#xff0c;分发规则&#xff08;注意&#xff0c;清空之前的防火墙iptable -F ; iptable -t nat…

linux Swap交换分区概念

Swap交换分区概念 什么是Linux swap space呢&#xff1f;我们先来看看下面两段关于Linux swap space的英文介绍资料: Linux divides its physical RAM (random access memory) into chucks of memory called pages. Swapping is the process whereby a page of memory is copie…

ThinkPHP 数据库操作(七) : 视图查询、子查询、原生查询

视图查询 视图查询可以实现不依赖数据库视图的多表查询&#xff0c;并不需要数据库支持视图&#xff0c;例如&#xff1a; Db::view(User,id,name)->view(Profile,truename,phone,email,Profile.user_idUser.id)->view(Score,score,Score.user_idProfile.id)->where(…

C++中的结构体函数

代码 #include "stdafx.h"structTest{ intnum; Test() { printf("11111111"); } Test(inti) { this->numi; } voidfun() { printf("fun"); }};voidmain( void){ Test a(1); …

Linux 查看进程的命令

1、ps ps -x : 只显示当前用户下的所有进程信息 ps -aux : 所有用户下的进程信息 2、top 显示动态的进程信息&#xff0c;5s刷新一次&#xff1b; 3、htop 需要自己安装htop命令&#xff0c;比较牛&#xff0c;个人也只是简单使用过&#xff0c;比top命令快&#xff0c;可…

关于安卓手机在微信浏览器中无法调起相机的原因

最近功在做公司的一个项目&#xff0c;遇到安卓手机在微信浏览器中更换头像无法调起相机的问题&#xff0c;特来此记录一下。 1.微信没有相机权限&#xff0c;开启就行了。 2.〈input type“file” accept“image/*”/〉。图库和相机都能调起。 3.部分冷门手机因系统原因不开放…

使用Microsoft Media Service实现网络影音多媒体应用系列第三篇---技术要点

技术要点解说&#xff1a; l 对Media Service的引用 Imports Microsoft.WindowsMediaServices.Interop Imports System.Runtime.InteropServices 引入以上两个命名空间以后&#xff0c;就可以看到WMSServer这个类&#xff0c;它就是指向Media Service的类。Activator.CreateIn…

SEO新手入门笔记

2019独角兽企业重金招聘Python工程师标准>>> 上个月公司让我给产品网站做SEO&#xff0c;第一次做这种事情&#xff0c;从中学到一些新东西&#xff0c;在这里做一个总结。 什么是SEO SEO是“搜索引擎优化”的简称&#xff0c;目的是提升网站在搜索引擎结果中的排名…

学习进度(4)

记录时间&#xff1a; 第五周 所花时间&#xff08;包括上课&#xff09; 10h 代码量&#xff08;行&#xff09; 200行 博客量&#xff08;篇&#xff09; 0篇 了解到的知识点 深入学习数据库语句 转载于:https://www.cnblogs.com/quxiangjia/p/10676086.html

linux top 命令的结果

PID&#xff1a;进程标志号&#xff0c;是非零正整数USER&#xff1a;进程所有者的用户名PR&#xff1a;进程的优先级别NI&#xff1a;进程的优先级别数值VIRT&#xff1a;进程占用的虚拟内存值RES&#xff1a;进程占用的物理内存值SHR&#xff1a;进程使用的共享内存值S&#…

从语义开始 – 概念、意义、实践

从语义开始 – 概念、意义、实践http://bbs.blueidea.com/thread-2944769-1-1.html 转载于:https://www.cnblogs.com/javashi/archive/2010/05/21/1741019.html

通过Python脚本理解系统进程间通信

from socket import * #导入socket包中的所有内容from time import ctime #导入time包&#xff0c;同时在本地可使用ctime进行调用import os,sys #导入os&#xff0c;sys包HOSTlocalhost#定义主机PORT21567#定义端口BUFSIZ1024 #定义缓冲区ADDR(HOST,PORT) #定义元组tcpSerSoc…

EnterpriseDB Replication,复制Oracle数据测试(1)

EntepriseDB 复制软件目前支持多种数据库到postgre的复制&#xff0c;其基本结构由发布者(Publication)与订阅者(Subscriptions)组成,Replication软件可针对来自不同类型数据库的多个发布者&#xff0c;将其数据复制到多个订阅者(Subscriptions)数据库中。 其可能的几种拓扑结构…

远程桌面登录 Windows Server 2003时提示无权限

2019独角兽企业重金招聘Python工程师标准>>> 登录时弹出提示&#xff1a;要登录到这台远程计算机&#xff0c;您必须被授予允许通过终端服务登录的权限。默认地&#xff0c;"远程桌面用户"组的成员拥有该权限。如果您不是"远程桌面用户"组或其它…