题意:

完成两个操作:

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. [转] 三步将你的 React Native 项目运行在 Web 浏览器上面

    React Native 的出现,让前端工程师拥有了使用 JavaScript 编写原生 APP 的能力.相比之前的 Web app 来说,对于性能和用户体验提升了非常多. 但是 React Nati ...

  2. app 的内存优化

    这篇文章是笔者在开发App过程中发现的一些内存问题, 然后学习了YYKit框架时候也发现了图片的缓存处理 (YYKit 作者联系了我, 说明了YYKit重写imageNamed:的目的不是为了内存管理 ...

  3. 好用的log

    Log.getStackTraceString(new Throwable())

  4. 兼容IE浏览器的placeholder【超不错】

    jQuery EnPlaceholder plug (兼容IE浏览器的placeholder)使用 >>>>>>>>>>>>&g ...

  5. hdu 3450 Counting Sequences

    /* n*n暴力 这个很好想 */ #include<cstdio> #define maxn 100010 #define mod 9901 using namespace std; i ...

  6. 补充一下sql server(临时表)

    说明:(1).临时表其实是放在数据库tempdb里的一个用户表:(2).TempTableName必须带“#”,“#"可以是一个或者两个,以#(局部)或##(全局)开头的表,这种表在会话期间 ...

  7. Zend Server安装后首次运行就出现Internal Server Error的解决

    无论是使用哪个版本的Zend Server来搭建PHP服务器,首次运行都会出现Internal Server Error的错误,对很多新手而言,每当看到这种错误时,那一刻内心绝对都是崩溃的.然而,这个 ...

  8. UITableViewCell 左滑删除

    - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { return Y ...

  9. 342. Power of Four

    题目: Given an integer (signed 32 bits), write a function to check whether it is a power of 4. Example ...

  10. 258. Add Digits(C++)

    258. Add Digits Given a non-negative integer num, repeatedly add all its digits until the result has ...