题目链接or Here

题意:n个数,有两个操作:1.修改某个数为v;2.询问一段区间第k小的数

如果没有修改,则可以用线段树,每个节点P[a,b]存储大小为b-a+1的数组,代表其中的数

同时,这个数组还是要排好序的

直接找答案很不方便,于是考虑对数组二分答案,求比它小的数的个数

关于构造过程,更新完子节点后,子节点维护的数组就是有序的了,可以通过归并得到父节点的有序数组

这样空间 \(O(nlogn)\),每次查询时间 \(O(log^2n)\)

修改同时有序,二叉排序树是好选择

线段树每个节点维护一棵平衡树,查询时在平衡树中查询;

修改一个点就将它从平衡树中删掉,更改后再插入(所有包含这个点的区间都要执行)

空间复杂度为 \(O(dep*n)\),dep为线段树的深度,大约就是 \(O(nlogn)\)

时间 \(O(nlog^3n)\)

树状数组+主席树见这.

整体二分见这.

//41644 kb  2404 ms
#include<cstdio>
#include<cctype>
#define gc() getchar()
//#define gc() (SS==TT &&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1e5+5,M=15*N,MAXIN=5e6; int n,q,tot,A[N],root[N],size,fa[M],son[M][2],sz[M],cnt[M],t[M];
char IN[MAXIN],*SS=IN,*TT=IN; inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
} inline void Update(int rt)
{
sz[rt]=sz[son[rt][0]]+sz[son[rt][1]]+cnt[rt];
}
void Rotate(int x,int &k)
{
int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
if(a==k) k=x;
else son[b][son[b][1]==a]=x;
fa[x]=b, fa[a]=x, fa[son[x][r]]=a,
son[a][l]=son[x][r], son[x][r]=a;
Update(a), Update(x);
}
void Splay(int x,int &k)
{
while(x!=k)
{
int a=fa[x],b=fa[a];
if(a!=k)
{
if((son[a][0]==x)^(son[b][0]==a)) Rotate(x,k);
else Rotate(a,k);
}
Rotate(x,k);
}
}
void Get_Rank(int v,int x)
{
if(!root[x]) return;//!
int k=root[x];
while(t[k]!=v && son[k][v>t[k]]) k=son[k][v>t[k]];
Splay(k,root[x]);
}
void Insert(int v,int x)
{
int f=0,k=root[x];
while(k && v!=t[k]) f=k,k=son[k][v>t[k]];
if(k) ++cnt[k];
else
{
k=++size, cnt[k]=sz[k]=1, t[k]=v, fa[k]=f;
if(f) son[f][v>t[f]]=k;
}
Splay(k,root[x]);
}
void Delete(int v,int x)
{
Get_Rank(v,x);
int k=root[x];
if(cnt[k]>1) {--cnt[k],--sz[k]; return;}
else if(!son[k][0]||!son[k][1]) root[x]=son[k][0]|son[k][1];
else
{
int p=son[k][0];
k=son[k][1], root[x]=k;//!
while(son[k][0]) k=son[k][0];
sz[k]+=sz[p], fa[p]=k, son[k][0]=p;
Splay(k,root[x]);
}
fa[root[x]]=0;//!
}
void Build(int l,int r,int rt,int pos)
{
Insert(A[pos],rt);
if(l==r) return;
int m=l+r>>1;
if(pos<=m) Build(l,m,rt<<1,pos);
else Build(m+1,r,rt<<1|1,pos);
}
void Modify(int l,int r,int rt,int pos,int v)
{
// printf("Modify:%d~%d rt:%d pos:%d v:%d\n",l,r,rt,pos,v);
Delete(A[pos],rt), Insert(v,rt);
if(l>=r) return;
int m=l+r>>1;
if(pos<=m) Modify(l,m,rt<<1,pos,v);
else Modify(m+1,r,rt<<1|1,pos,v);
}
void Calc(int v,int k)
{
while(k)
{
// printf("k:%d v:%d tot:%d\n",k,v,tot);
if(v==t[k]) {tot+=sz[son[k][0]]; return;}
if(v>t[k]) tot+=sz[son[k][0]]+cnt[k],k=son[k][1];
else k=son[k][0];
}
}
void Query(int l,int r,int rt,int L,int R,int v)
{
// printf("Query:%d~%d rt:%d L~R:%d~%d v:%d\n",l,r,rt,L,R,v);
if(L<=l && r<=R) {Calc(v,root[rt]); return;}
int m=l+r>>1;
if(L<=m) Query(l,m,rt<<1,L,R,v);
if(m<R) Query(m+1,r,rt<<1|1,L,R,v);
} int main()
{
#ifndef ONLINE_JUDGE
freopen("1901.in","r",stdin);
// freopen("1901.out","w",stdout);
#endif n=read(),q=read();
for(int i=1;i<=n;++i) A[i]=read(),Build(1,n,1,i);
char s[5];
int i,j,k;
while(q--)
{
scanf("%s",s),i=read(),j=read();
if(s[0]=='C') Modify(1,n,1,i,j),A[i]=j;
else
{
k=read();
int l=0,r=1e9,m,ans=0;
while(l<=r)
{
m=l+r>>1;
tot=0, Query(1,n,1,i,j,m);
// printf("%d~%d %d\n",l,r,tot);
if(tot>=k) r=m-1;
else l=m+1,ans=m;
}
printf("%d\n",ans);
}
} return 0;
}

BZOJ.1901.Dynamic Rankings(线段树套平衡树 Splay)的更多相关文章

  1. [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

    题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...

  2. bzoj 1901 Dynamic Rankings (树状数组套线段树)

    1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB Description 给定一个含有n个数的序列a[1] ...

  3. BZOJ.1901.Dynamic Rankings(树状数组套主席树(动态主席树))

    题目链接 BZOJ 洛谷 区间第k小,我们可以想到主席树.然而这是静态的,怎么支持修改? 静态的主席树是利用前缀和+差分来求解的,那么对于每个位置上的每棵树看做一个点,拿树状数组更新. 还是树状数组的 ...

  4. bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description ...

  5. bzoj 2120 线段树套平衡树

    先吐下槽,改了快一个小时,最后发现是SBT的delete写错了,顿时就有想死的心..... 首先对于这道题,我们应该先做一下他的小问题,bzoj1878,虽然和这道题几乎一点关系没有, 但是能给我们一 ...

  6. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  7. 树套树Day1线段树套平衡树bzoj3196

    您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查 ...

  8. BZOJ.1901.Dynamic Rankings(整体二分)

    题目链接 BZOJ 洛谷 (以下是口胡) 对于多组的询问.修改,我们可以发现: 假设有对p1,p2,p3...的询问,在这之前有对p0的修改(比如+1),且p0<=p1,p2,p3...,那么我 ...

  9. 【BZOJ-3196】二逼平衡树 线段树 + Splay (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2271  Solved: 935[Submit][Stat ...

随机推荐

  1. jquery筛选数组之grep、each、inArray、map的用法及遍历son对象(转)

    grep [传入的参数为返回bool类型的函数] <script type='text/javascript' src="/jquery.js"></script ...

  2. linux 查看cpu的使用百分比

    先安装 sudo apt-get install sysstat 然后: mpstat -u 2 5

  3. Shell 中test 单中括号[] 双中括号[[]] 的区别

    Shell test 单中括号[] 双中括号[[]] 的区别 在写Shell脚本的时候,经常在写条件判断语句时不知道该用[] 还是 [[]],首先我们来看他们的类别: $type [ [[ test ...

  4. java 基础(转自索宁)

    一.方法函数 函数也称为方法,就是定义在类中的具有特定功能的一段独立代码.用于定义功能,提高代码的复用性. 函数的特点1> 定义函数可以将功能代码进行封装,便于对该功能进行复用:2> 函数 ...

  5. PYTHON-流程控制之if/while/for-练习

    # 1 练习题## 简述编译型与解释型语言的区别,且分别列出你知道的哪些语言属于编译型,哪些属于解释型# 编译型:C, 谷歌翻译,一次翻译后结果后重复使用# 解释型:Python, 同声传译,边执行边 ...

  6. 从零开始自己搭建复杂网络2(以Tensorflow为例)

    从零开始自己搭建复杂网络(以DenseNet为例) DenseNet 是一种具有密集连接的卷积神经网络.在该网络中,任何两层之间都有直接的连接,也就是说,网络每一层的输入都是前面所有层输出的并集, 而 ...

  7. Windows Mac地址伪装步骤

    本文介绍Windows上Mac地址修改方法,适用于网络环境绑定了Mac地址需要修改上网的情况. 工具/原料 PC电脑一台 Windows系统 方法/步骤 点击右下角图标. 点击打开网络和共享中心. 点 ...

  8. ubuntu chrome 安装ubuntu16.04 : google浏览器安装及离线插件安装(谷歌访问助手)

    1.https://blog.csdn.net/cheneykl/article/details/79187954 https://download.oracle.com/otn-pub/java/j ...

  9. 步步为营-47-分页显示的SQL语句

    说明:分页显示在实际业务中经常需要用到,其SQL语句分两种 1:分页显示SQL语句 --方法一:跳过多少行,选中多少行 --每页n条,选择第m页--n= m= --)*n 主键 from 表); se ...

  10. 胖哈勃杯Pwn400、Pwn500详解

    概述 这次的胖哈博杯我出了Pwn400.Pwn500两道题目,这里讲一下出题和解题的思路.我个人感觉前两年的Pwn题更多的是考察单一的利用技巧,比我这有个洞怎么利用它拿到权限.但是我研究了一些最近的题 ...