题意:

完成两个操作:

1.询问一个区间里第k小的数;

2.修改数列中一个数的值。

分析:

线段树套平衡树,线段树中的每个节点都有一棵平衡树,维护线段树所记录的这个区间的元素。
这样处理空间上是O(nlogn)的,因为线段树有logn层,每层的平衡树所记的节点总数都有n个。
修改很容易想到,把所有包含要修改点的区间的平衡树都修改了就行了

查询使用二分答案的方法

// File Name: 2112.cpp
// Author: Zlbing
// Created Time: 2013年10月07日 星期一 18时24分39秒
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,r,n) for(int i=r;i<=n;i++)
#define RREP(i,n,r) for(int i=n;i>=r;i--)
#define lson l,m,root<<1
#define rson m+1,r,root<<1|1
const int MAXN=5e4+;
//线段树套平衡树,线段树中的每个结点都有一颗平衡树,维护线段树所记录
//的这个区间的元素
//rt数组是维护线段树的数组,表示线段树结点中的平衡树的根
//对于spaly树中的修改只要将rt修改成rt[root]并传递root参数
struct SplayTree {
int sz[MAXN*];
int ch[MAXN*][];
int pre[MAXN*];
int top;
int rt[MAXN<<];
inline void up(int x){
sz[x] = cnt[x] + sz[ ch[x][] ] + sz[ ch[x][] ];
}
inline void Rotate(int x,int f){
int y=pre[x];
ch[y][!f] = ch[x][f];
pre[ ch[x][f] ] = y;
pre[x] = pre[y];
if(pre[x]) ch[ pre[y] ][ ch[pre[y]][] == y ] =x;
ch[x][f] = y;
pre[y] = x;
up(y);
}
inline void Splay(int x,int goal,int root){//将x旋转到goal的下面
while(pre[x] != goal){
if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][] == x);
else {
int y=pre[x],z=pre[y];
int f = (ch[z][]==y);
if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f);
else Rotate(y,f),Rotate(x,f);
}
}
up(x);
if(goal==) rt[root]=x;
}
inline void RTO(int k,int goal,int root){//将第k位数旋转到goal的下面
int x=rt[root];
while(sz[ ch[x][] ] != k-) {
if(k < sz[ ch[x][] ]+) x=ch[x][];
else {
k-=(sz[ ch[x][] ]+);
x = ch[x][];
}
}
Splay(x,goal,root);
}
inline void vist(int x){
if(x){
printf("结点%2d : 左儿子 %2d 右儿子 %2d %2d sz=%d\n",x,ch[x][],ch[x][],val[x],sz[x]);
vist(ch[x][]);
vist(ch[x][]);
}
}
inline void Newnode(int &x,int c){
x=++top;
ch[x][] = ch[x][] = pre[x] = ;
sz[x]=; cnt[x]=;
val[x] = c;
}
inline void init(){
top=;
}
inline void Insert(int &x,int key,int f,int root){
if(!x) {
Newnode(x,key);
pre[x]=f;
Splay(x,,root);
return ;
}
if(key==val[x]){
cnt[x]++;
sz[x]++;
return ;
}else if(key<val[x]) {
Insert(ch[x][],key,x,root);
} else {
Insert(ch[x][],key,x,root);
}
up(x);
} void Del(int root){ //删除根结点
if(cnt[rt[root]]>)
{
cnt[rt[root]]--;
}
else
{
int t=rt[root];
if(ch[rt[root]][]) {
rt[root]=ch[rt[root]][];
RTO(,,root);
ch[rt[root]][]=ch[t][];
if(ch[rt[root]][]) pre[ch[rt[root]][]]=rt[root];
}
else rt[root]=ch[rt[root]][];
pre[rt[root]]=;
}
up(rt[root]);
}
void findpre(int x,int key,int &ans){ //找key前趋
if(!x) return ;
if(val[x] <= key){
ans=x;
findpre(ch[x][],key,ans);
} else
findpre(ch[x][],key,ans);
}
void findsucc(int x,int key,int &ans){ //找key后继
if(!x) return ;
if(val[x]>=key) {
ans=x;
findsucc(ch[x][],key,ans);
} else
findsucc(ch[x][],key,ans);
}
void findkey(int x,int key,int &ans)//找key
{
if(!x)return;
if(val[x]==key)
ans=x;
else if(val[x]>key)
findkey(ch[x][],key,ans);
else
findkey(ch[x][],key,ans);
}
//找第K大数
inline int find_kth(int x,int k,int root){
if(k<sz[ch[x][]]+) {
return find_kth(ch[x][],k,root);
}else if(k > sz[ ch[x][] ] + cnt[x] )
return find_kth(ch[x][],k-sz[ch[x][]]-cnt[x],root);
else{
Splay(x,,root);
return val[x];
}
}
int cnt[MAXN*];
int val[MAXN*];
//---------------------------------------------
//建立线段树和线段树中的每个结点的平衡树
void build(int l,int r,int root)
{
rt[root]=;
for(int i=l;i<=r;i++)
Insert(rt[root],a[i],,root);
if(l>=r)return;
int m=(l+r)>>;
build(lson);
build(rson);
}
void update(int l,int r,int root,int i,int x)
{
int ans=;
findkey(rt[root],a[i],ans);
Splay(ans,,root);
Del(root);
Insert(rt[root],x,,root); if(l>=r)return;
int m=(l+r)>>;
if(i<=m)update(lson,i,x);
else update(rson,i,x);
}
int cntLess(int x,int key)
{
int ret=;
while(x)
{
if(val[x]>key)
x=ch[x][];
else
{
ret+=cnt[x]+sz[ch[x][]];
x=ch[x][];
}
}
return ret;
}
int getnumLess(int l,int r,int root,int L,int R,int x)
{
if(L<=l&&R>=r)
return cntLess(rt[root],x);
int m=(l+r)>>;
int ret=;
if(L<=m)ret+=getnumLess(lson,L,R,x);
if(R>m)ret+=getnumLess(rson,L,R,x);
return ret;
}
int search(int L,int R,int k)
{
int l=,r=INF;
int ans=;
while(l<=r)
{
int m=(l+r)>>;
int cnt=getnumLess(,n,,L,R,m);
if(cnt>=k)
{
r=m-;
ans=m;
}
else l=m+;
}
return ans;
}
void solve()
{
scanf("%d%d",&n,&m);
REP(i,,n)
scanf("%d",&a[i]);
build(,n,);
REP(i,,m)
{
int x,y,z;
char str[];
scanf("%s",str);
if(str[]=='C')
{
scanf("%d%d",&x,&y);
update(,n,,x,y);
a[x]=y;
}
else
{
scanf("%d%d%d",&x,&y,&z);
int k=search(x,y,z);
printf("%d\n",k);
}
}
}
int a[MAXN];
int n,m; }spt;
int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
spt.init();
spt.solve();
}
return ;
}

ZOJ-2112-Dynamic Rankings(线段树套splay树)的更多相关文章

  1. ZOJ - 2112 Dynamic Rankings(BIT套主席树)

    纠结了好久的一道题,以前是用线段树套平衡树二分做的,感觉时间复杂度和分块差不多了... 终于用BIT套函数式线段树了过了,120ms就是快,此题主要是卡内存. 假设离散后有ns个不同的值,递归层数是l ...

  2. 主席树[可持久化线段树](hdu 2665 Kth number、SP 10628 Count on a tree、ZOJ 2112 Dynamic Rankings、codeforces 813E Army Creation、codeforces960F:Pathwalks )

    在今天三黑(恶意评分刷上去的那种)两紫的智推中,突然出现了P3834 [模板]可持久化线段树 1(主席树)就突然有了不详的预感2333 果然...然后我gg了!被大佬虐了! hdu 2665 Kth ...

  3. ZOJ 2112 Dynamic Rankings(动态区间第 k 大+块状链表)

    题目大意 给定一个数列,编号从 1 到 n,现在有 m 个操作,操作分两类: 1. 修改数列中某个位置的数的值为 val 2. 询问 [L, R] 这个区间中第 k 大的是多少 n<=50,00 ...

  4. 整体二分&cdq分治 ZOJ 2112 Dynamic Rankings

    题目:单点更新查询区间第k大 按照主席树的思想,要主席树套树状数组.即按照每个节点建立主席树,然后利用树状数组的方法来更新维护前缀和.然而,这样的做法在实际中并不能AC,原因即卡空间. 因此我们采用一 ...

  5. 整体二分(SP3946 K-th Number ZOJ 2112 Dynamic Rankings)

    SP3946 K-th Number (/2和>>1不一样!!) #include <algorithm> #include <bitset> #include & ...

  6. zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap

    Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/show ...

  7. ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  8. ZOJ 2112 Dynamic Rankings (动态第 K 大)(树状数组套主席树)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  9. 高级数据结构(树状数组套主席树):ZOJ 2112 Dynamic Rankings

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  10. ZOJ 2112 Dynamic Rankings(树状数组套主席树 可修改区间第k小)题解

    题意:求区间第k小,节点可修改 思路:如果直接用静态第k小去做,显然我更改一个节点后,后面的树都要改,这个复杂度太高.那么我们想到树状数组思路,树状数组是求前缀和,那么我们可以用树状数组套主席树,求出 ...

随机推荐

  1. windows 与Linux 互传文件

    下载putty,将putty的安装路径添加到Windows的环境变量中:     我的电脑->属性->高级->环境变量->系统变量,双击其中的Path,在分号后添加putty的 ...

  2. Android(java)学习笔记208:Android中操作JSON数据(Json和Jsonarray)

    1.Json 和 Xml       JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的 ...

  3. Ant学习笔记(2) 在Eclipse中使用Ant

    Eclipse默认提供了对Ant的支持,在Eclipse中不需要安装任何插件就能直接编辑和运行Ant.Eclipse中包含了一个Ant脚本编辑器,Ant脚本编辑器提供了对Ant脚本的语法搞来高亮.自动 ...

  4. JAVA 生成PDF报表()

    许多应用程序都要求动态生成 PDF 文档.这些应用程序涵盖从生成客户对帐单并通过电子邮件交付的银行到购买特定的图书章节并以 PDF 格式接收这些图书章节的读者.这个列表不胜枚举.在本文中,我们将使用 ...

  5. Java环境的安装与配置

    Java环境的安装与配置 环境:Java8,win10 推荐oracle官网oracle官网https://www.oracle.com/index.html下载JDK进行安装 选择自己需要的版本下载 ...

  6. 受限玻尔兹曼机(RBM)

    能量模型 RBM用到了能量模型. 简单的概括一下能量模型.假设一个孤立系统(总能量$E$一定,粒子个数$N$一定),温度恒定为1,每个粒子有$m$个可能的状态,每个状态对应一个能量$e_i$.那么,在 ...

  7. UIAlertController (UIActionSheet, UIAlertView is deprecated in iOS 8.)

    iOS 8 后 UIAlertView 和  UIActionSheet 都被合并到了 UIAlertController里面. 文档原文: Important: UIAlertView is dep ...

  8. c#wiform中KeyDown事件

    当首次按下键盘上某个键时发生事件. 例如 private void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Ke ...

  9. winform(C#)拖拽实现获得文件路径

    设置Form的AllowDrop为true  private void Form1_DragDrop(object sender, DragEventArgs e)        {          ...

  10. css 不确定元素宽度的水平居中

    对于一个不确定宽度的元素居中,我们想到使用的方法是 text-align:center; 或者 margin:0 auto; text-align只对行内元素有效,对于块元素我们要用margin,块元 ...