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. convert-Csharp-DateTime-Ticks-to-js

    <!DOCTYPE html> <html> <head> <script> function myFunction() { var b = forma ...

  2. leetcode-累加数(C++)

    累加数是一个字符串,组成它的数字可以形成累加序列. 一个有效的累加序列必须至少包含 3 个数.除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和. 给定一个只包含数字 '0'-'9'  ...

  3. lintcode First Unique Number In Stream

    First Unique Number In Stream 描述: Given a continuous stream of numbers, write a function that return ...

  4. Redis4.0支持的新功能说明

    本文以华为云DCS for Redis版本为例,介绍Redis4.0的新功能.文章转载自华为云帮助中心. 与Redis3.x版本相比,DCS的Redis4.x以上版本,除了开源Redis增加的特性之外 ...

  5. [Install] TeamViewer

    安装TeamViwer 1. $ sudo apt-get -f install 2. 使用gdebi安装TeamViwer. 所以先安装gdebi package. $ sudo apt-get i ...

  6. Trie 树——搜索关键词提示

    当你在搜索引擎中输入想要搜索的一部分内容时,搜索引擎就会自动弹出下拉框,里面是各种关键词提示,这个功能是怎么实现的呢?其实底层最基本的就是 Trie 树这种数据结构. 1. 什么是 "Tri ...

  7. ZOJ 2532 Internship(最大流找关键割边)

    Description CIA headquarter collects data from across the country through its classified network. Th ...

  8. nodejs笔记--基础篇(一)

    Sublime Node.js开发环境配置 下载并安装Node.js安装包后再开始配置 1.先安装好Sublime Text 2 2.运行Sublime,菜单上找到Tools ---> Buil ...

  9. 【转】再谈PHP、Python与Ruby

    原文链接:http://www.nowamagic.net/librarys/veda/detail/2504 一句话总结 简单地总结: 假如你想帮他尽快找个活儿,赚到钱,推荐PHP. 假如你想让他成 ...

  10. js经典试题之数据类型

    js经典试题之数据类型 1:输出"B" + "a" + + "B" + "a"的值: 答案:BaNaNa. 分析:因为+ ...