BZOJ3196 & 洛谷3380:二逼平衡树——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3196
https://www.luogu.org/problemnew/show/P3380
(题面用洛谷的)
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
查询k在区间内的排名
查询区间内排名为k的值
修改某一位值上的数值
查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)
查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)
参考:https://blog.csdn.net/clove_unique/article/details/51279573
其实看参考博客就行了,线段树套splay极限卡时间。
简单解释一下第二种操作:
因为线段树没法查这个,所以一种直观的想法是二分答案。
但由于周多麻烦的因素,我们存所有元素再排个序的效率并不高,于是我们直接对值域二分。
但是显然有些值在这里面是没有的,所以要有一种很妙的判断手段。
我们对于mid求出它在区间内之前有多少值,和k比较,如果比k小就不要。
这样最后我们应该能够找到比该元素小的数有k+1个且最小的元素,且并不难证明这个元素-1的值一定在树中有。
(因为这个元素-1如果不存在的话就应该有k+1个比它小,和“最小的元素”矛盾。)
(人生第一棵树套树,感觉良好,卡常卡的质疑人生。)
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=;
const int N=4e6+;
inline int read(){
int X=,w=;char ch=;
while(ch<''||ch>''){w|=ch=='-';ch=getchar();}
while(ch>=''&&ch<='')X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
int s[N],maxn,rt[N],sz;
int fa[N],tr[N][],key[N],size[N],cnt[N];
inline bool get(int x){
return tr[fa[x]][]==x;
}
inline void clear(int x){
fa[x]=tr[x][]=tr[x][]=key[x]=cnt[x]=size[x]=;
}
inline void splay_upd(int x){
if(!x)return;
size[x]=cnt[x];
if(tr[x][])size[x]+=size[tr[x][]];
if(tr[x][])size[x]+=size[tr[x][]];
}
inline void rotate(int x){
int y=fa[x],z=fa[y],which=get(x);
tr[y][which]=tr[x][which^];fa[tr[y][which]]=y;
fa[y]=x;tr[x][which^]=y;fa[x]=z;
if(z)tr[z][tr[z][]==y]=x;
splay_upd(y);splay_upd(x);
}
inline void splay(int i,int x){
int f=fa[x];
while(f){
if(fa[f])rotate(get(x)==get(f)?f:x);
rotate(x);f=fa[x];
}
rt[i]=x;
}
inline void splay_ins(int i,int v){
if(!rt[i]){
rt[i]=++sz;
fa[sz]=tr[sz][]=tr[sz][]=;
size[sz]=cnt[sz]=;key[sz]=v;
return;
}
int now=rt[i],f=;
while(){
if(key[now]==v){
cnt[now]++;splay_upd(f);splay(i,now);
return;
}
f=now;now=tr[now][key[now]<v];
if(!now){
++sz;
fa[sz]=f;tr[sz][]=tr[sz][]=;
size[sz]=cnt[sz]=;key[sz]=v;
tr[f][key[f]<v]=sz;
splay_upd(f);splay(i,sz);
return;
}
}
}
inline int splay_find(int i,int v){//查询比v小的数的个数
int ans=,now=rt[i];
while(){
if(!now)return ans;
if(v<key[now])now=tr[now][];
else{
ans+=(tr[now][]?size[tr[now][]]:);
if(v==key[now]){
splay(i,now);
return ans;
}
ans+=cnt[now];
now=tr[now][];
}
}
}
inline int splay_pre(int i){
int now=tr[rt[i]][];
while(tr[now][])now=tr[now][];
return now;
}
inline int splay_nxt(int i){
int now=tr[rt[i]][];
while(tr[now][])now=tr[now][];
return now;
}
inline void splay_del(int i,int x){
splay_find(i,x);
if(cnt[rt[i]]>){
cnt[rt[i]]--;return;
}
if(!tr[rt[i]][]&&!tr[rt[i]][]){
clear(rt[i]);rt[i]=;return;
}
if(!tr[rt[i]][]){
int oldroot=rt[i];rt[i]=tr[rt[i]][];fa[rt[i]]=;clear(oldroot);return;
}
else if(!tr[rt[i]][]){
int oldroot=rt[i];rt[i]=tr[rt[i]][];fa[rt[i]]=;clear(oldroot);return;
}
int leftbig=splay_pre(i),oldroot=rt[i];
splay(i,leftbig);
fa[tr[oldroot][]]=rt[i];
tr[rt[i]][]=tr[oldroot][];
clear(oldroot);
splay_upd(rt[i]);
}
inline void seg_mdy(int a,int l,int r,int x,int v){
splay_del(a,s[x]);splay_ins(a,v);
if(l==r)return;
int mid=(l+r)>>;
if(x<=mid)seg_mdy(a<<,l,mid,x,v);
else seg_mdy(a<<|,mid+,r,x,v);
}
inline int seg_find(int a,int l,int r,int l1,int r1,int v){
if(r<l1||r1<l)return ;
if(l1<=l&&r<=r1)return splay_find(a,v);
int mid=(l+r)>>;
return seg_find(a<<,l,mid,l1,r1,v)+seg_find(a<<|,mid+,r,l1,r1,v);
}
inline int seg_pre(int a,int l,int r,int l1,int r1,int v){
if(r<l1||r1<l)return -INF;
if(l1<=l&&r<=r1){
splay_ins(a,v);
int tmp=splay_pre(a);
splay_del(a,v);
return !tmp?-INF:key[tmp];
}
int mid=(l+r)>>;
return max(seg_pre(a<<,l,mid,l1,r1,v),seg_pre(a<<|,mid+,r,l1,r1,v));
}
inline int seg_nxt(int a,int l,int r,int l1,int r1,int v){
if(r<l1||r1<l)return INF;
if(l1<=l&&r<=r1){
splay_ins(a,v);
int tmp=splay_nxt(a);
splay_del(a,v);
return !tmp?INF:key[tmp];
}
int mid=(l+r)>>;
return min(seg_nxt(a<<,l,mid,l1,r1,v),seg_nxt(a<<|,mid+,r,l1,r1,v));
}
inline void seg_build(int a,int l,int r){
for(int i=l;i<=r;i++)splay_ins(a,s[i]);
if(l==r)return;
int mid=(l+r)>>;
seg_build(a<<,l,mid);seg_build(a<<|,mid+,r);
}
int main(){
int n=read(),m=read();
for(int i=;i<=n;++i){
s[i]=read(),maxn=max(maxn,s[i]);
}
seg_build(,,n);
for(int i=;i<=m;++i){
int op=read();
if(op==){
int l=read(),r=read(),k=read();
printf("%d\n",seg_find(,,n,l,r,k)+);
}
if(op==){
int l=read(),r=read(),k=read();
int l1=,r1=maxn+;
while(l1<r1){
int mid=(l1+r1)>>;
int rk=seg_find(,,n,l,r,mid);
if(rk<k)l1=mid+;
else r1=mid;
}
printf("%d\n",l1-);
}
if(op==){
int pos=read(),k=read();
seg_mdy(,,n,pos,k);
s[pos]=k;maxn=max(maxn,s[pos]);
}
if(op==){
int l=read(),r=read(),k=read();
printf("%d\n",seg_pre(,,n,l,r,k));
}
if(op==){
int l=read(),r=read(),k=read();
printf("%d\n",seg_nxt(,,n,l,r,k));
}
}
return ;
}
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +
+++++++++++++++++++++++++++++++++++++++++++
BZOJ3196 & 洛谷3380:二逼平衡树——题解的更多相关文章
- 洛谷P3380 二逼平衡树
线段树+平衡树 我!又!被!卡!常!了! 以前的splay偷懒的删除找前驱后继的办法被卡了QAQ 放一个在洛谷开O2才能过的代码..我太菜了.. #include <bits/stdc++.h& ...
- [luogu3380][bzoj3196]【模板】二逼平衡树【树套树】
题目地址 [洛谷传送门] 题目大意 区间查询k的排名,查找k排名的数,单点修改,区间前驱,区间后继. 感想 真的第一次写树套树,整个人都不对了.重构代码2次,发现样例都过不了,splay直接爆炸,可能 ...
- 【BZOJ3196】Tyvj 1730 二逼平衡树
Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的 ...
- 【bzoj3196】Tyvj 1730 二逼平衡树 线段树套Treap
题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义 ...
- 洛谷 P2015 二叉苹果树 题解
题面 裸的树上背包: 设f[u][i]表示在以u为子树的树种选择i条边的最大值,则:f[u][i]=max(f[u][i],f[u][i-j-1]+f[v][k]+u到v的边权); #include ...
- 洛谷 P3380 bzoj3196 Tyvj1730 【模板】二逼平衡树(树套树)
[模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数值 查询k在 ...
- 洛谷P3380 【模板】二逼平衡树(树套树)(线段树+树状数组)
P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...
- 洛谷 P3380 【模板】二逼平衡树(树套树)-线段树套splay
P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...
- 【题解】二逼平衡树 [P3380] [BZOJ3196] [Tyvj1730]
[题解]二逼平衡树 [P3380] [BZOJ3196] [Tyvj1730] 传送门:[模板]二逼平衡树(树套树)\([P3380]\) \([BZOJ3196]\) \([TYVJ1730]\) ...
随机推荐
- VueJs 学习笔记
VueJs学习笔记 参考资料:https://cn.vuejs.org/ 特效库:TweenJS(补间动画库) VelocityJS(轻量级JS动画库) Animate.css(CSS预设动画库) ...
- 180602-nginx多域名配置
文章链接:https://liuyueyi.github.io/hexblog/2018/06/02/180602-nginx多域名配置/ nginx多域名配置 原来的域名过期了,重新买了一个hhui ...
- 为什么测试人员必须掌握Linux?
相信点进来的小伙伴不是对Linux感兴趣就是对测试感兴趣了,也希望本文可以帮助之前接触过Linux的小伙伴找到继续坚持学习下去的动力,之前没接触过Linux的小伙伴也能找到开始学习Linux的兴趣. ...
- 内置方法(item系列)
class Foo: def __init__(self,name): self.name = name def __getitem__(self, item): # 获取时触发 print('get ...
- 【if控制器】-(某种情况成立就执行的场景)
if 控制器 一般来判断某种特殊情况 成立,就执行. JEXL Expression to evaluate:此处直接填写需要进行判断的表达式即可 表达式支持: == 是否等于,如${__jex ...
- 在github上面创建属于自己的个性主页
圈子里面越来越多的同事在github上面创建自己的项目文档,那里确实高手云集,海内外的技术大牛小牛们都在那儿有一席之地,为“helloword”贡献自己. 以上感慨略过... 这几日正想创建一个自己的 ...
- Nodejs Express笔记
Express做服务器,主要考虑到可能存在的高并发,js写起来也并不麻烦,环境搭建也异常简单.开车~ 由于主要目的就是用于生产环境,所以肯定不能用高版本的Nodejs,选LTS,没错的. 一.安装 这 ...
- 有关WCSF的几点整理
本文示例代码 一.CreateNew Attribute实现属性注入 Steps: 1/ aspx创建某个服务的属性. 2/ 为其添加[CreateNew] Attribute. 3/ 页面继承自Mi ...
- c#,mysql,读取乱码问题
1.首先保证数据库的表是UTF8类型:数据库是否是utf8无关紧要: 2.c#连接数据库语句添加“charset=utf8”一句:.exe.config是否添加这一句也无关紧要: 3.访问数据库数据用 ...
- Median of Two Sorted Arrays(hard)
题目要求: 有两个排序的数组nums1和nums2分别为m和n大小. 找到两个排序数组的中位数.整体运行时间复杂度应为O(log(m + n)). 示例: 我的方法: 分别逐个读取两个数组的数,放到一 ...