题目链接

  幸甚至哉,歌以咏志。

  拿下了曾经是那么遥不可及的线段树,学会了曾经高不可攀的平衡树,弄懂了装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)相关推荐

  1. 树套树 ----- 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],我们要减去[ ...

  2. 【用学校抄作业带你走进可持久化线段树(主席树)】可持久化线段树概念+全套模板+例题入门:[福利]可持久化线段树)

    我似乎很少写这种算法博客 可持久化线段树概念 概念介绍(类比帮助理解) 简单分析一下时间和空间复杂度(内容池) 模板 结构体变量 建树模板 单点修改模板 单点查询模板 区间修改模板(pushup) 区 ...

  3. 动态区间第k小:树状数组套权值线段树

    所谓树状数组套权值线段树,就是在树状树组上套权值线段树 (逃) 解析 如何解决静态区间第k小? 使用主席树就ok啦 辣么如何解决动态区间第k小嘞- 我们想想主席树为啥不能解决动态区间第k小 因为如果改 ...

  4. 【BZOJ3295】动态逆序对,CDQ分治/BIT套权值线段树

    传送门 思路: 用来练习cdq的题目 断断续续纠结了2天 因为loli一直在考试 最后莫名乱搞了一发就A了? 实际上是考虑每一次修改对答案的贡献,即位置在1~x-1且大于x的数以及位置在x+1~n且小 ...

  5. 数据结构:树套树-替罪羊树套权值线段树

    BZOJ3065 本题是在BZOJ上的处女A,实在不应该拿这样一道题来开头 平衡树套线段树应该是树套树问题里比较难的一种了,当然我记得还有一个替罪羊树套Trie树的题,我是不信自己能写出来的. 外层的 ...

  6. Luogu P4246 [SHOI2008]堵塞的交通(线段树+模拟)

    P4246 [SHOI2008]堵塞的交通 题意 题目描述 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个\(2\)行\(C\)列的矩形 ...

  7. 势能线段树(吉司机线段树)专题

    势能线段树(吉司机线段树)专题 势能线段树在近期训练时遇到了好几次,但是由于本人太懒一直没补完,结果ICPC网络赛还真就出了一道势能线段树Orz--结果当然是没做出来--痛定思痛,这回把之前欠的一块儿 ...

  8. AcWing 蓝桥杯AB组辅导课 05、树状数组与线段树

    文章目录 前言 一.树状数组 1.1.树状数组知识点 1.2.树状数组代码模板 模板题:AcWing 1264. 动态求连续区间和 例题 例题1.AcWing 1265. 数星星[中等,信息学奥赛一本 ...

  9. 如何在vs中创建r树索引代码_线段树详解与实现

    此篇文章用于记录<玩转数据结构>课程的学习笔记 什么是线段树 线段树也被称为区间树,英文名为Segment Tree或者Interval tree,是一种高级的数据结构.这种数据结构更多出 ...

  10. 树状数组及线段树入门(SDNU1665-1668)

    目录 前言 树状数组 先导 单点修改区间查询 区间修改区间查询 线段树 先导 单点修改区间查询--递归形式 单点修改区间查询--非递归形式 区间修改区间查询--递归形式 区间修改区间查询--非递归形式 ...

最新文章

  1. R语言shiny包运行runApp()报错的解决
  2. Android教程之android数据库编程
  3. python下载的文件放在哪里的-Python下载文件的方法
  4. 树莓派命令连接wifi_树莓派连接无线网wifi配置方法
  5. 最新综述:多标签学习的新趋势
  6. Windows下源码获取
  7. dan.php,shenlingdan.php
  8. 股东接连减持 寒武纪2021年净亏损8.47亿元
  9. Java-Volatile的实现(待删除)
  10. 这算抄百度?Google为信息流告别简洁搜索框,也押注短视频
  11. 浅谈WebService开发二(同步与异步调用)转
  12. jQuery Mobile中按钮button的data-*选项
  13. table 谷歌下不出现滚动条
  14. 大数据时代侦查机制有哪些改变
  15. 基于springboot人事管理系统设计与实现
  16. 写一彩票程序,要求能随机产生并按照升序输出1-30之间的7个数,且其中任意两个数字不能重复
  17. 网络扫描及安全评估实验实验报告
  18. 《数据清洗》 第六章 数据转换
  19. 投射数据卷Secret、ConfigMap、DownwardAPI
  20. 从作者的角度去阅读一本书-一种全新的阅读体验

热门文章

  1. 计算机软件429修复工具,Soft4Boost Any Uninstaller
  2. 约瑟夫环 猴子选大王的问题
  3. 第三方快递接口API调用
  4. ajax请求url 绝对路径与相对路径
  5. 遍历Linux kernel的链表时删除元素的方法
  6. 利用XShell上传、下载文件(使用sz与rz命令),超实用!
  7. 算法建模流程详解及python代码实现
  8. 频率概率与贝叶斯概率
  9. 逻辑推理篇:数据分析中违背常理的悖论:辛普森悖论
  10. python学习笔记(四)字典(dict)