【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,right using std::max;
using std::min; inline int read(){
int num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} int s[];
int q[]; struct Node{
int e[],fa,val,size,sum;
}tree[];
int tot,point;
inline void update(int x){
tree[x].size=tree[x].sum;
if(tree[x].e[]) tree[x].size+=tree[tree[x].e[]].size;
if(tree[x].e[]) tree[x].size+=tree[tree[x].e[]].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[]; }
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^];
connect(b,y,sony);
connect(y,x,sony^);
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);
else
if(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=;
return tot;
} inline void Delete(int x){
tree[x].e[]=tree[x].e[]=;
if(x==tot) tot--;
} int build(int val,int rt){
point++;
if(!s[rt]){ s[rt]=create(val,); return s[rt];}
else{
int now=s[rt];
while(){
tree[now].size++;
if(val==tree[now].val){ tree[now].sum++; return now; }
int nxt=val<tree[now].val?:;
if(!tree[now].e[nxt]){
create(val,now);
tree[now].e[nxt]=tot;
return tot;
}
now=tree[now].e[nxt];
}
}
return ;
} 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 ;
now=tree[now].e[nxt];
}
} void pop(int val,int rt){
int deal=find(val,rt);
if(!deal) return;
point--;
if(tree[deal].sum>){ tree[deal].sum--; tree[deal].size--; return; }
if(!tree[deal].e[]){ s[rt]=tree[deal].e[]; tree[s[rt]].fa=; }
else{
int le=tree[deal].e[];
while(tree[le].e[]) le=tree[le].e[];
splay(le,tree[deal].e[],rt);
int ri=tree[deal].e[];
connect(ri,le,); s[rt]=le;
update(le);
}
Delete(deal);
} int rank(int val,int rt){
int ans=,now=s[rt];
while(){
//printf("%d %d\n",now,tree[now].sum);
if(val<tree[now].val){
now=tree[now].e[];
if(!now) return ans;
}
else{
if(tree[now].e[]) ans+=tree[tree[now].e[]].size;
if(val==tree[now].val||!tree[now].e[]){
if(val>tree[now].val) ans+=tree[now].sum;
splay(now,s[rt],rt);
return ans;
}
ans+=tree[now].sum; now=tree[now].e[];
}
}
} inline int lower(int val,int rt){
int ans=-,now=s[rt];
while(){
if(!now) return ans;
if(tree[now].val<val&&tree[now].val>ans) ans=tree[now].val;
int nxt=val>tree[now].val?:;
now=tree[now].e[nxt];
}
} inline int upper(int val,int rt){
int ans=,now=s[rt];
while(){
if(!now) return ans;
if(tree[now].val>val&&tree[now].val<ans) ans=tree[now].val;
int nxt=val>tree[now].val?:;
now=tree[now].e[nxt];
}
} int lows(int val,int rt){
int ans=-,now=s[rt];
while(){
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?:;
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=;
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=-;
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=;
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=;i<=n;++i) q[i]=read();
Build(,n,);
for(register int i=;i<=m;++i){
int opt=read();
if(opt==){
int l=read(),r=read(),q=read();
printf("%d\n",findrank(l,r,q,,n,)+);
}
else if(opt==){
int l=read(),r=read(),q=read();
int a=,b=1e8,Ans=;
while(a<=b){
int m=(a+b)>>;
int x=lows(m,);
if(findrank(l,r,x,,n,)+>q) b=m-;
else{
a=m+;
Ans=x;
}
}
printf("%d\n",Ans);
}
else if(opt==){
int l=read(),r=read();
Update(l,r,,n,);
q[l]=r;
}
else if(opt==){
int l=read(),r=read(),q=read();
printf("%d\n",findlower(l,r,q,,n,));
}
else if(opt==){
int l=read(),r=read(),q=read();
printf("%d\n",findupper(l,r,q,,n,));
}
}
return ;
}
【Luogu】P3380树套树模板(线段树套Splay)的更多相关文章
- [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)
[BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...
- hdu 1754 I Hate It (模板线段树)
http://acm.hdu.edu.cn/showproblem.php?pid=1754 I Hate It Time Limit: 9000/3000 MS (Java/Others) M ...
- BZOJ2141排队——树状数组套权值线段树(带修改的主席树)
题目描述 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家 乐和和.红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别 ...
- luogu3380/bzoj3196 二逼平衡树 (树状数组套权值线段树)
带修改区间K大值 这题有很多做法,我的做法是树状数组套权值线段树,修改查询的时候都是按着树状数组的规则找出那log(n)个线段树根,然后一起往下做 时空都是$O(nlog^2n)$的(如果离散化了的话 ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- CF1093E Intersection of Permutations 树状数组套权值线段树
\(\color{#0066ff}{ 题目描述 }\) 给定整数 \(n\) 和两个 \(1,\dots,n\) 的排列 \(a,b\). \(m\) 个操作,操作有两种: \(1\ l_a\ r_a ...
- Dynamic Rankings(树状数组套权值线段树)
Dynamic Rankings(树状数组套权值线段树) 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[ ...
- 【bzoj3065】带插入区间K小值 替罪羊树套权值线段树
题目描述 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出 ...
- Luogu P4246 [SHOI2008]堵塞的交通(线段树+模拟)
P4246 [SHOI2008]堵塞的交通 题意 题目描述 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个\(2\)行\(C\)列的矩形 ...
- luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树
LINK:字符串树 先说比较简单的正解.由于我没有从最简单的考虑答案的角度思考 所以... 下次还需要把所有角度都考察到. 求x~y的答案 考虑 求x~根+y~根-2*lca~根的答案. 那么问题变成 ...
随机推荐
- 对话框窗口最大化盖住任务栏问题!OnGetMinMaxInfo,WM_GETMINMAXINFO
http://hi.baidu.com/csacer/item/37cd6ac2dec18d360831c6a7 在写程序时,如果包含了标题栏,但是没有包含最大化按钮或者最小话按钮,那么人工用Show ...
- LINUX一网卡多IP设置
方法1:少量IP手动绑定(这里以绑定IP到eth0为例,其它网卡的话修改相应的文件名即可) 1.复制ifcfg-eth0的网卡配置文件并改名为ifcfg-eth0:0 [root@akinlau /] ...
- 分布式系统中的CAP原理和BASE理论
CAP是一致性(Consistency).可用性(Availability).分区容忍性(Partition tolerance)的缩写.CAP原理指的是这三个要素最多只能同时实现两点,不可能三者兼顾 ...
- SQL 数学串函数
数学函数 ceiling 取上限 floor 取下限 round 四舍五入 len 长度 abs 绝对值 PI()圆周率 sqrt 开根号 qwuare 平方根 select 10 ...
- Integer比较浅析
//Integer 型比较假如是使用 == ,只能比较数值为-128~127数值; 在这个范围内使用的是自动装箱拆箱: //.intValue()使用这个需要确认属性不为null; //equals( ...
- Java面试题全集(下)
这部分主要是开源Java EE框架方面的内容,包括hibernate.MyBatis.spring.Spring MVC等,由于Struts 2已经是明日黄花,在这里就不讨论Struts 2的面试题, ...
- leetcode_1049. Last Stone Weight II_[DP]
1049. Last Stone Weight II https://leetcode.com/problems/last-stone-weight-ii/ 题意:从一堆石头里任选两个石头s1,s2, ...
- java 中设计模式
1. 单例模式(一个类只有一个实例) package ch.test.notes.designmodel; /** * Description: 单例模式 (饿汉模式 线程安全的) * * @auth ...
- Mybatis generator自动生成代码包括实体,dao,xml文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration ...
- QT +自定义控件-spin+slider
动手实现自定义控件: 1.首先在ui界面中添加一个(Widget)容器类.如图中的1所示 2.在项目中添加一个SmallWidget类,如下: 3.接着在程序编辑界面进行程序编辑如下: #includ ...