【Luogu】P3380树套树模板(线段树套Splay)
题目链接
幸甚至哉,歌以咏志。
拿下了曾经是那么遥不可及的线段树,学会了曾经高不可攀的平衡树,弄懂了装B的时候才挂在嘴边的树套树。
每道模板都是链上的一颗珠子。把它们挨个串起来,就成为我成长的历程。
抒情结束开始讲题
这道题我们用线段树存平衡树的根节点。比如我们有一棵线段树
这样子。线段树的一个节点 存 它表示的那个区间 所对应的 平衡树 的根节点编号。这样每个节点都拥有一棵平衡树。是不是很炫呢?
对于操作1我们就可以把所有零散的区间里比它小的数的个数都找出来,+1就是答案啦。
对于操作2我们可以二分数,然后不断地进行操作1.
对于操作3我们用logn的时间把所有包含这个点的区间都修改一遍。
对于操作4和操作5,不多讲了。
很炫吧
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cctype> #define mid ((l+r)>>1) #define left (rt<<1) #define right (rt<<1|1) #define lson l,mid,left #define rson mid+1,r,rightusing std::max; using std::min;inline int read(){int num=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}while(isdigit(ch)){num=num*10+ch-'0';ch=getchar();}return num*f; }int s[502000]; int q[102000];struct Node{int e[2],fa,val,size,sum; }tree[5002000]; int tot,point; inline void update(int x){tree[x].size=tree[x].sum;if(tree[x].e[0]) tree[x].size+=tree[tree[x].e[0]].size;if(tree[x].e[1]) tree[x].size+=tree[tree[x].e[1]].size; } inline void connect(int x,int fa,int how){ tree[x].fa=fa; tree[fa].e[how]=x; } inline int iden(int x){ return x==tree[tree[x].fa].e[1]; } void rotate(int x,int rt){int y=tree[x].fa; int r=tree[y].fa;if(y==s[rt]) s[rt]=x;int sony=iden(x); int sonr=iden(y);int b=tree[x].e[sony^1];connect(b,y,sony);connect(y,x,sony^1);connect(x,r,sonr);update(y); update(x); }void splay(int pos,int to,int rt){to=tree[to].fa;while(tree[pos].fa!=to){if(tree[tree[pos].fa].fa==to) rotate(pos,rt);elseif(iden(pos)==iden(tree[pos].fa)){ rotate(tree[pos].fa,rt); rotate(pos,rt); }else { rotate(pos,rt); rotate(pos,rt); }} }inline int create(int val,int fa){tree[++tot].val=val;tree[tot].fa=fa;tree[tot].sum=tree[tot].size=1;return tot; }inline void Delete(int x){tree[x].e[0]=tree[x].e[1]=0;if(x==tot) tot--; }int build(int val,int rt){point++;if(!s[rt]){ s[rt]=create(val,0); return s[rt];}else{int now=s[rt];while(1){tree[now].size++;if(val==tree[now].val){ tree[now].sum++; return now; }int nxt=val<tree[now].val?0:1;if(!tree[now].e[nxt]){create(val,now);tree[now].e[nxt]=tot;return tot;}now=tree[now].e[nxt];}}return 0; }inline void insert(int val,int rt){int p=build(val,rt);splay(p,s[rt],rt); }int find(int val,int rt){int now=s[rt];while(now){if(tree[now].val==val){ splay(now,s[rt],rt); return now; }int nxt=val>tree[now].val;if(!tree[now].e[nxt]) return 0;now=tree[now].e[nxt];} }void pop(int val,int rt){int deal=find(val,rt);if(!deal) return;point--;if(tree[deal].sum>1){ tree[deal].sum--; tree[deal].size--; return; }if(!tree[deal].e[0]){ s[rt]=tree[deal].e[1]; tree[s[rt]].fa=0; }else{int le=tree[deal].e[0];while(tree[le].e[1]) le=tree[le].e[1];splay(le,tree[deal].e[0],rt);int ri=tree[deal].e[1];connect(ri,le,1); s[rt]=le;update(le);}Delete(deal); }int rank(int val,int rt){int ans=0,now=s[rt];while(1){//printf("%d %d\n",now,tree[now].sum);if(val<tree[now].val){now=tree[now].e[0];if(!now) return ans;}else{if(tree[now].e[0]) ans+=tree[tree[now].e[0]].size;if(val==tree[now].val||!tree[now].e[1]){if(val>tree[now].val) ans+=tree[now].sum;splay(now,s[rt],rt);return ans;}ans+=tree[now].sum; now=tree[now].e[1];}} }inline int lower(int val,int rt){int ans=-2147483647,now=s[rt];while(1){if(!now) return ans;if(tree[now].val<val&&tree[now].val>ans) ans=tree[now].val;int nxt=val>tree[now].val?1:0;now=tree[now].e[nxt];} }inline int upper(int val,int rt){int ans=2147483647,now=s[rt];while(1){if(!now) return ans;if(tree[now].val>val&&tree[now].val<ans) ans=tree[now].val;int nxt=val>tree[now].val?1:0;now=tree[now].e[nxt];} }int lows(int val,int rt){int ans=-2147483647,now=s[rt];while(1){if(!now) return ans;if(tree[now].val<=val&&tree[now].val>ans) ans=tree[now].val;if(tree[now].val==val) return ans;int nxt=val>tree[now].val?1:0;now=tree[now].e[nxt];} }void Build(int l,int r,int rt){if(l>r) return;if(l==r){insert(q[l],rt);return;}Build(lson);Build(rson);for(int i=l;i<=r;++i) insert(q[i],rt);return; }int findrank(int from,int to,int num,int l,int r,int rt){if(from<=l&&to>=r) return rank(num,rt);int ans=0;if(from<=mid) ans+=findrank(from,to,num,lson);if(to>mid) ans+=findrank(from,to,num,rson);return ans; }void Update(int o,int num,int l,int r,int rt){pop(q[o],rt);insert(num,rt);if(l==r) return;if(o<=mid) Update(o,num,lson);else Update(o,num,rson); }int findlower(int from,int to,int num,int l,int r,int rt){if(from<=l&&to>=r) return lower(num,rt);int ans=-2147483647;if(from<=mid) ans=max(ans,findlower(from,to,num,lson));if(to>mid) ans=max(ans,findlower(from,to,num,rson));return ans; }int findupper(int from,int to,int num,int l,int r,int rt){if(from<=l&&to>=r) return upper(num,rt);int ans=2147483647;if(from<=mid) ans=min(ans,findupper(from,to,num,lson));if(to>mid) ans=min(ans,findupper(from,to,num,rson));return ans; }int main(){int n=read(),m=read();for(int i=1;i<=n;++i) q[i]=read();Build(1,n,1);for(register int i=1;i<=m;++i){int opt=read();if(opt==1){int l=read(),r=read(),q=read();printf("%d\n",findrank(l,r,q,1,n,1)+1);}else if(opt==2){int l=read(),r=read(),q=read();int a=0,b=1e8,Ans=0;while(a<=b){int m=(a+b)>>1;int x=lows(m,1);if(findrank(l,r,x,1,n,1)+1>q) b=m-1;else{a=m+1;Ans=x;}}printf("%d\n",Ans);}else if(opt==3){int l=read(),r=read();Update(l,r,1,n,1);q[l]=r;}else if(opt==4){int l=read(),r=read(),q=read();printf("%d\n",findlower(l,r,q,1,n,1));}else if(opt==5){int l=read(),r=read(),q=read();printf("%d\n",findupper(l,r,q,1,n,1));}}return 0; }
转载于:https://www.cnblogs.com/cellular-automaton/p/8041493.html
【Luogu】P3380树套树模板(线段树套Splay)相关推荐
- 树套树 ----- P1975 [国家集训队]排队(树状数组套权值线段树求动态逆序对)
解题思路: 首先我们知道交换两个数a[l]和a[r]a[l]和a[r]a[l]和a[r]影响到的区间是[l+1,r−1][l+1,r-1][l+1,r−1] 对于a[l]a[l]a[l],我们要减去[ ...
- 【用学校抄作业带你走进可持久化线段树(主席树)】可持久化线段树概念+全套模板+例题入门:[福利]可持久化线段树)
我似乎很少写这种算法博客 可持久化线段树概念 概念介绍(类比帮助理解) 简单分析一下时间和空间复杂度(内容池) 模板 结构体变量 建树模板 单点修改模板 单点查询模板 区间修改模板(pushup) 区 ...
- 动态区间第k小:树状数组套权值线段树
所谓树状数组套权值线段树,就是在树状树组上套权值线段树 (逃) 解析 如何解决静态区间第k小? 使用主席树就ok啦 辣么如何解决动态区间第k小嘞- 我们想想主席树为啥不能解决动态区间第k小 因为如果改 ...
- 【BZOJ3295】动态逆序对,CDQ分治/BIT套权值线段树
传送门 思路: 用来练习cdq的题目 断断续续纠结了2天 因为loli一直在考试 最后莫名乱搞了一发就A了? 实际上是考虑每一次修改对答案的贡献,即位置在1~x-1且大于x的数以及位置在x+1~n且小 ...
- 数据结构:树套树-替罪羊树套权值线段树
BZOJ3065 本题是在BZOJ上的处女A,实在不应该拿这样一道题来开头 平衡树套线段树应该是树套树问题里比较难的一种了,当然我记得还有一个替罪羊树套Trie树的题,我是不信自己能写出来的. 外层的 ...
- Luogu P4246 [SHOI2008]堵塞的交通(线段树+模拟)
P4246 [SHOI2008]堵塞的交通 题意 题目描述 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个\(2\)行\(C\)列的矩形 ...
- 势能线段树(吉司机线段树)专题
势能线段树(吉司机线段树)专题 势能线段树在近期训练时遇到了好几次,但是由于本人太懒一直没补完,结果ICPC网络赛还真就出了一道势能线段树Orz--结果当然是没做出来--痛定思痛,这回把之前欠的一块儿 ...
- AcWing 蓝桥杯AB组辅导课 05、树状数组与线段树
文章目录 前言 一.树状数组 1.1.树状数组知识点 1.2.树状数组代码模板 模板题:AcWing 1264. 动态求连续区间和 例题 例题1.AcWing 1265. 数星星[中等,信息学奥赛一本 ...
- 如何在vs中创建r树索引代码_线段树详解与实现
此篇文章用于记录<玩转数据结构>课程的学习笔记 什么是线段树 线段树也被称为区间树,英文名为Segment Tree或者Interval tree,是一种高级的数据结构.这种数据结构更多出 ...
- 树状数组及线段树入门(SDNU1665-1668)
目录 前言 树状数组 先导 单点修改区间查询 区间修改区间查询 线段树 先导 单点修改区间查询--递归形式 单点修改区间查询--非递归形式 区间修改区间查询--递归形式 区间修改区间查询--非递归形式 ...
最新文章
- R语言shiny包运行runApp()报错的解决
- Android教程之android数据库编程
- python下载的文件放在哪里的-Python下载文件的方法
- 树莓派命令连接wifi_树莓派连接无线网wifi配置方法
- 最新综述:多标签学习的新趋势
- Windows下源码获取
- dan.php,shenlingdan.php
- 股东接连减持 寒武纪2021年净亏损8.47亿元
- Java-Volatile的实现(待删除)
- 这算抄百度?Google为信息流告别简洁搜索框,也押注短视频
- 浅谈WebService开发二(同步与异步调用)转
- jQuery Mobile中按钮button的data-*选项
- table 谷歌下不出现滚动条
- 大数据时代侦查机制有哪些改变
- 基于springboot人事管理系统设计与实现
- 写一彩票程序,要求能随机产生并按照升序输出1-30之间的7个数,且其中任意两个数字不能重复
- 网络扫描及安全评估实验实验报告
- 《数据清洗》 第六章 数据转换
- 投射数据卷Secret、ConfigMap、DownwardAPI
- 从作者的角度去阅读一本书-一种全新的阅读体验