https://www.lydsy.com/JudgeOnline/problem.php?id=3196

https://www.luogu.org/problemnew/show/P3380

(题面用洛谷的)

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

  1. 查询k在区间内的排名

  2. 查询区间内排名为k的值

  3. 修改某一位值上的数值

  4. 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)

  5. 查询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:二逼平衡树——题解的更多相关文章

  1. 洛谷P3380 二逼平衡树

    线段树+平衡树 我!又!被!卡!常!了! 以前的splay偷懒的删除找前驱后继的办法被卡了QAQ 放一个在洛谷开O2才能过的代码..我太菜了.. #include <bits/stdc++.h& ...

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

    题目地址 [洛谷传送门] 题目大意 区间查询k的排名,查找k排名的数,单点修改,区间前驱,区间后继. 感想 真的第一次写树套树,整个人都不对了.重构代码2次,发现样例都过不了,splay直接爆炸,可能 ...

  3. 【BZOJ3196】Tyvj 1730 二逼平衡树

    Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的 ...

  4. 【bzoj3196】Tyvj 1730 二逼平衡树 线段树套Treap

    题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义 ...

  5. 洛谷 P2015 二叉苹果树 题解

    题面 裸的树上背包: 设f[u][i]表示在以u为子树的树种选择i条边的最大值,则:f[u][i]=max(f[u][i],f[u][i-j-1]+f[v][k]+u到v的边权); #include ...

  6. 洛谷 P3380 bzoj3196 Tyvj1730 【模板】二逼平衡树(树套树)

    [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数值 查询k在 ...

  7. 洛谷P3380 【模板】二逼平衡树(树套树)(线段树+树状数组)

    P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...

  8. 洛谷 P3380 【模板】二逼平衡树(树套树)-线段树套splay

    P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...

  9. 【题解】二逼平衡树 [P3380] [BZOJ3196] [Tyvj1730]

    [题解]二逼平衡树 [P3380] [BZOJ3196] [Tyvj1730] 传送门:[模板]二逼平衡树(树套树)\([P3380]\) \([BZOJ3196]\) \([TYVJ1730]\) ...

随机推荐

  1. Myeclipse - 问题集 - specified vm install not found

    In Eclipse, click the ant file -- Run As -- External Tools Configuration and click on the JRE tab. S ...

  2. 基于Docker的UI自动化初探

    本文来自网易云社区 前言 一直以来,项目迭代的时间都是比较紧张的,开发加班加点coding,测试加班加点提bug.都说"时间像海绵里的水,挤挤总会有的"(当然这里的"挤挤 ...

  3. Consul初体验

      Preface       Today I'm gonna implement a consul in my environment to discover service of MySQL da ...

  4. 180620-mysql之数据库导入导出

    文章链接:https://liuyueyi.github.io/hexblog/2018/06/20/180620-mysql之数据库导入导出/ mysql之数据库导入导出 实际工作中,需要做一下数据 ...

  5. 制作一个App的完整流程是哪些

    APP开发流程其实并不复杂,但是对于客户来说,.一般移动APP开发都离不开UI设计师.前端开发.后端开发.测试专员.产品经理等,由于他们的工作性质都不一样,我们且先把APP软件开发项目分为三个阶段: ...

  6. 即刻开始使用Kotlin开发Android的12个原因(KAD 30)

    作者:Antonio Leiva 时间:Jul, 11, 2017 原文链接:https://antonioleiva.com/reasons-kotlin-android/ 这组文章已到最后了,它们 ...

  7. GIt学习第二天之版本回退、工作区和暂存区

    搬运自 ‘廖雪峰的官方网站’ 地址:https://www.liaoxuefeng.com/ 1.版本回退 在Git中,我们用git log命令显示从最近到最远的提交日志,如果嫌输出信息太多,看得眼花 ...

  8. 第六章 高级I/O函数

    第六章 高级I/O函数 6.1 pipe函数 即管道函数,用于进程间的通信. #include<unistd.h> int pipe(int fd[2]); // fd:filedes / ...

  9. python 终极篇 ---django 认证

    Django自带的用户认证 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能,这还真是个麻烦的事情呢. Djang ...

  10. jQuery官网plugins栏目下那些不错的插件

    前言: 很久以前就关注过jQuery官网plugins栏目下那些全是英文的插件,本人的英文水平很菜,想要全部看懂确实是件不易之事. 好在大部分的案例中都有 view-homepage 或 Try a ...