ZOJ-2112-Dynamic Rankings(线段树套splay树)
题意:
完成两个操作:
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树)的更多相关文章
- ZOJ - 2112 Dynamic Rankings(BIT套主席树)
纠结了好久的一道题,以前是用线段树套平衡树二分做的,感觉时间复杂度和分块差不多了... 终于用BIT套函数式线段树了过了,120ms就是快,此题主要是卡内存. 假设离散后有ns个不同的值,递归层数是l ...
- 主席树[可持久化线段树](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 ...
- ZOJ 2112 Dynamic Rankings(动态区间第 k 大+块状链表)
题目大意 给定一个数列,编号从 1 到 n,现在有 m 个操作,操作分两类: 1. 修改数列中某个位置的数的值为 val 2. 询问 [L, R] 这个区间中第 k 大的是多少 n<=50,00 ...
- 整体二分&cdq分治 ZOJ 2112 Dynamic Rankings
题目:单点更新查询区间第k大 按照主席树的思想,要主席树套树状数组.即按照每个节点建立主席树,然后利用树状数组的方法来更新维护前缀和.然而,这样的做法在实际中并不能AC,原因即卡空间. 因此我们采用一 ...
- 整体二分(SP3946 K-th Number ZOJ 2112 Dynamic Rankings)
SP3946 K-th Number (/2和>>1不一样!!) #include <algorithm> #include <bitset> #include & ...
- zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap
Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/show ...
- ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树)
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
- ZOJ 2112 Dynamic Rankings (动态第 K 大)(树状数组套主席树)
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
- 高级数据结构(树状数组套主席树):ZOJ 2112 Dynamic Rankings
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
- ZOJ 2112 Dynamic Rankings(树状数组套主席树 可修改区间第k小)题解
题意:求区间第k小,节点可修改 思路:如果直接用静态第k小去做,显然我更改一个节点后,后面的树都要改,这个复杂度太高.那么我们想到树状数组思路,树状数组是求前缀和,那么我们可以用树状数组套主席树,求出 ...
随机推荐
- Gitolite轻松部署/管理git server
对于今天越来越受欢迎的Git,相信做开发的朋友都基本有所耳闻.它最大的便利就是分布式的开发库,让使用git作为源码管理库的开发者可以在本地提交代码的修改而不用提交到远程的库,同时需要和团队协作.同步代 ...
- rabbitmq 消息持久化
rabbitmq 消息持久化 2016-02-18 11:19 224人阅读 评论(0) 收藏 举报 分类: 综合(15) 版权声明:本文为博主原创文章,未经博主允许不得转载. 二: 任务分发 & ...
- POS tagging的解釋
轉錄文章~~ 什么是词性标注(POS tagging) Tue, 04/13/2010 - 10:36 — Fuller 词性标注也叫词类标注,POS tagging是part-of-speech t ...
- Java-Android 之电话拨号源码
file:///F:/workspace3/Android_ver2.4/src/cn/szy/com/MainActivity.java package cn.szy.com; import and ...
- .NET Core跨平台开发
对于.NET开源计划想必关注的人已经跃跃欲试了,但是真正将其用于开发的目前来说不多.毕竟截至本文发布时.NET Core才发布到1.0RC2版本.正式版预计还有一段时间.况且大多数人都是持观望态度,就 ...
- 多列的行列转换(PIVOT,UNPIVOT)
形式1 形式2 形式3 有时候可能会有这样的需求: 将一张表的所有列名转做为数据的一列数据,将一列数据作为整张表的列名 当列比较多时,只用PIVOT是解决不了的,经过研究,需要将UNPIVOT 和 P ...
- jQuery AJAX实现调用页面后台方法
1.新建demo.aspx页面.2.首先在该页面的后台文件demos.aspx.cs中添加引用. using System.Web.Services; 3.无参数的方法调用. 大家注意了,这个版本不能 ...
- Tensor神经网络进行知识库推理
本文是我关于论文<Reasoning With Neural Tensor Networks for Knowledge Base Completion>的学习笔记. 一.算法简介 网络的 ...
- asp.net发布和更新网站
我们一般使用ftp软件来更新网站,而更新之前的一个步骤就是发布项目.以下将讲解asp.net mvc如何发布网站. 打开项目 右键点击项目,选择“发布” 第一次发布前,需要配置一下发布配置文件:点击” ...
- 使用Qt创建第一个OpenCV的Gui应用
写在前面 学习OpenCV有一些小日子了,发现群里还有很多初学OpenCV的人像我当初一样跌跌撞撞到处找资料,所以在这里把学习笔记分享给大家,希望有志学习OpenCV进行计算机视觉活动的小伙伴们能少走 ...