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. GitLab 自动触发 Jenkins 构建

    GitLab 是当前应用非常广泛的 Git Hosting 工具,Jenkins 是非常牛逼的持续集成工具.尽管 GitLab 有内建的 GitLab CI,但它远没有 Jenkins 那么强大好用. ...

  2. ACID、数据库隔离级别

    ACID: A(Atomicity):原子性,要么全部执行,要么都不执行 C(consistency):一致性: 特点: 1.一个操作除法级联,这些必须成功,否则全部失败(原子性) 2.所有节点同步更 ...

  3. 「知识学习&日常训练」莫队算法(一)(Codeforce Round #340 Div.2 E)

    题意 (CodeForces 617E) 已知一个长度为\(n\)的整数数列\(a[1],a[2],-,a[n]\),给定查询参数\(l,r\),问\([l,r]\)内,有多少连续子段满足异或和等于\ ...

  4. C 判断成绩是否及格

    #include <stdio.h> int main(int argc, char **argv) { // 新建两个变量  pass代表及格分数的固定变量 score代表学生成绩的一个 ...

  5. Python全栈 项目(电子词典、协程、pdb调试)

    后面我就不截图了 大家还是看原文吧                          https://yq.aliyun.com/articles/629534 . ................. ...

  6. Vue-cli 工具 / 通过 Vue-cli 工具重构 todoList

    本博文归纳在 Vue 学习过程中, Vue-cli 工具的使用说明.除此之外还通过 Vue-cli 工具将之前 Vuejs 基本语法当中实现的 todoList 进行重构. 安装 npm instal ...

  7. Dask教程

    Dask 介绍 Dask是一款用于分析计算的灵活并行计算库. Dask由两部分组成: 针对计算优化的动态任务调度.这与Airflow,Luigi,Celery或Make类似,但针对交互式计算工作负载进 ...

  8. 计蒜客蓝桥杯模拟赛 后缀字符串:STL_map+贪心

    问题描述 一天蒜头君得到 n 个字符串 si​,每个字符串的长度都不超过 10. 蒜头君在想,在这 n 个字符串中,以 si​ 为后缀的字符串有多少个呢? 输入格式 第一行输入一个整数 n. 接下来  ...

  9. C struct中的位域 bitfield

    C struct中的位域 bitfield 结构体的成员可以限制其位域,每个成员可以使用用比字节还小的取值范围,下面的结构体s1中,四个成员每个成员都是2bit的值(0~3),整个结构体占据的空间依然 ...

  10. BAT 批处理脚本 教程 【转】

    BAT 批处理脚本 教程 第一章 批处理基础 第一节 常用批处理内部命令简介 批处理定义:顾名思义,批处理文件是将一系列命令按一定的顺序集合为一个可执行的文本文件,其扩展名为BAT或者CMD.这些命令 ...