bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)
3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MB
[Submit][Status][Discuss]
Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
Input
第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继
Output
对于操作1,2,4,5各输出一行,表示查询结果
Sample Input
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
Sample Output
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
#include<cstdio>
#include<algorithm>
using namespace std;
#define M 3000001
#define N 50001 int id=;
int siz[M],cnt[M],key[M];
int fa[M],ch[M][];
struct TREE
{
int root,l,r;
}tr[N<<];
int data[N];
void Splay_up(int k)
{
siz[k]=siz[ch[k][]]+siz[ch[k][]]+cnt[k];
}
void rotate(int x,int &goal)
{
int y=fa[x],z=fa[y];
int l=ch[y][]==x,r=l^;
if(y==goal) goal=x;
else ch[z][ch[z][]==y]=x;
ch[y][l]=ch[x][r]; ch[x][r]=y;
fa[x]=z; fa[y]=x; fa[ch[y][l]]=y;
Splay_up(y);
}
void splay(int x,int &goal)
{
int y,z;
while(x!=goal)
{
y=fa[x]; z=fa[y];
if(y!=goal)
{
if(ch[z][]==y ^ ch[y][]==x) rotate(x,goal);
else rotate(y,goal);
}
rotate(x,goal);
Splay_up(x);
}
}
void Splay_insert(int &rt,int w)
{
if(!rt)
{
rt=++id;
siz[rt]=cnt[rt]=;
key[rt]=w;
return;
}
if(key[rt]==w) cnt[rt]++;
else if(w<key[rt]) Splay_insert(ch[rt][],w),fa[ch[rt][]]=rt;
else Splay_insert(ch[rt][],w),fa[ch[rt][]]=rt;
Splay_up(rt);
}
int Splay_getpre(int rt,int x)
{
int now=rt,ret;
while(now)
{
if(key[now]>=x) now=ch[now][];
else ret=now,now=ch[now][];
}
return ret;
}
int Splay_getsuc(int rt,int x)
{
int now=rt,ret;
while(now)
{
if(key[now]<=x) now=ch[now][];
else ret=now,now=ch[now][];
}
return ret;
}
int Splay_number(int now,int w)
{
while()
{
if(key[now]==w) return now;
if(w<key[now]) now=ch[now][];
else now=ch[now][];
}
}
void del(int & rt,int w)
{
int num=Splay_number(rt,w);
splay(num,rt);
if(cnt[num]>) cnt[num]--, siz[num]--;
else
{
int pre=Splay_getpre(rt,w);
splay(pre,rt);
ch[pre][]=ch[num][];
fa[ch[pre][]]=pre;
Splay_up(pre);
}
}
void add_dummy(int rt,int w,int d)
{
ch[rt][d]=++id; siz[rt]++;
fa[id]=rt; siz[id]=cnt[id]=; key[id]=w;
} void build(int k,int l,int r)
{
tr[k].l=l; tr[k].r=r;
if(l==r) return;
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
}
void Segment_insert(int k,int pos,int w)
{
Splay_insert(tr[k].root,w);
if(tr[k].l==tr[k].r) return;
int mid=tr[k].l+tr[k].r>>;
if(pos<=mid) Segment_insert(k<<,pos,w);
else Segment_insert(k<<|,pos,w);
}
void dummy(int k)
{
int pre=Splay_getsuc(tr[k].root,-),suc=Splay_getpre(tr[k].root,1e8);
splay(pre,tr[k].root);
add_dummy(pre,-1e8-,);
splay(suc,tr[k].root);
add_dummy(suc,1e8+,);
if(tr[k].l==tr[k].r) return;
dummy(k<<); dummy(k<<|);
}
int order(int k,int opl,int opr,int w)
{
if(tr[k].l>=opl && tr[k].r<=opr)
{
int pre=Splay_getpre(tr[k].root,w);
splay(pre,tr[k].root);
return siz[ch[pre][]]+cnt[pre]-;
}
int mid=tr[k].l+tr[k].r>>,tmp=;
if(opl<=mid) tmp+=order(k<<,opl,opr,w);
if(opr>mid) tmp+=order(k<<|,opl,opr,w);
return tmp;
}
int Segment_number(int l,int r,int w)
{
int ll=,rr=1e8,mid,tmp,ans;
while(ll<=rr)
{
mid=ll+rr>>;
tmp=order(,l,r,mid);
if(tmp<w) ans=mid,ll=mid+;
else rr=mid-;
}
return ans;
}
void modify(int k,int pos,int before,int now)
{
del(tr[k].root,before);
Splay_insert(tr[k].root,now);
if(tr[k].l==tr[k].r)
{
data[tr[k].l]=now;
return;
}
int mid=tr[k].l+tr[k].r>>;
if(pos<=mid) modify(k<<,pos,before,now);
else modify(k<<|,pos,before,now);
}
int Segment_getpre(int k,int l,int r,int w)
{
if(tr[k].l>=l && tr[k].r<=r) return key[Splay_getpre(tr[k].root,w)];
int mid=tr[k].l+tr[k].r>>,tmp=-1e8-;
if(l<=mid) tmp=max(tmp,Segment_getpre(k<<,l,r,w));
if(r>mid) tmp=max(tmp,Segment_getpre(k<<|,l,r,w));
return tmp;
}
int Segment_getsuc(int k,int l,int r,int w)
{
if(tr[k].l>=l && tr[k].r<=r) return key[Splay_getsuc(tr[k].root,w)];
int mid=tr[k].l+tr[k].r>>,tmp=1e8+;
if(l<=mid) tmp=min(tmp,Segment_getsuc(k<<,l,r,w));
if(r>mid) tmp=min(tmp,Segment_getsuc(k<<|,l,r,w));
return tmp;
} int main()
{
freopen("psh.in","r",stdin);
freopen("psh.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
build(,,n);
for(int i=;i<=n;i++)
{
scanf("%d",&data[i]);
Segment_insert(,i,data[i]);
}
dummy();
int opt,l,r,k;
while(m--)
{
scanf("%d",&opt);
if(opt==)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",order(,l,r,k)+);
}
else if(opt==)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",Segment_number(l,r,k));
}
else if(opt==)
{
scanf("%d%d",&l,&k);
modify(,l,data[l],k);
}
else if(opt==)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",Segment_getpre(,l,r,k));
}
else
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",Segment_getsuc(,l,r,k));
}
}
}
bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)的更多相关文章
- bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1807 Solved: 772[Submit][Stat ...
- BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )
这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------- ...
- BZOJ 3196 Tyvj 1730 二逼平衡树 树套树 线段树 treap
http://www.lydsy.com/JudgeOnline/problem.php?id=3196 http://hzwer.com/2734.html 线段树套treap,似乎splay也可以 ...
- BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay
传送门 题意 给你一个长度为 $ n $ 有序数列 $ a $ ,进行 $ m $ 次操作,操作有如下几种: 查询 $ k $ 在区间 $ [l,r] $ 内的排名 查询区间 $ [l,r] $ 内排 ...
- BZOJ - 3196 Tyvj 1730 二逼平衡树 (线段树套treap)
题目链接 区间线段树套treap,空间复杂度$O(nlogn)$,时间复杂度除了查询区间k大是$O(log^3n)$以外都是$O(log^2n)$的. (据说线段树套线段树.树状数组套线段树也能过?) ...
- bzoj 3196 Tyvj 1730 二逼平衡树【线段树 套 splay】
四舍五入就是个暴力. 对于线段树的每个区间都开一棵按权值排序的splay 对于第二个操作,二分一下,每次查询mid的排名,复杂度 $ O(nlog(n)^{3}) $ 其余的操作都是$ O(nlog( ...
- bzoj 3196: Tyvj 1730 二逼平衡树
#include<cstdio> #include<ctime> #include<cstdlib> #include<iostream> #defin ...
- BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树
[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> ...
- BZOJ3196二逼平衡树——线段树套平衡树(treap)
此为平衡树系列最后一道:二逼平衡树您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询 ...
随机推荐
- 推荐形参使用常量引用:void func(const T &);
一.声明为const的原因: 把函数不会改变的形参定义成普通的引用会带给函数的调用者一种误导,即函数可以修改它的实参的值: 限制函数所能接受的实参类型,如不能把const对象.字面值或者需要类型转换的 ...
- c# 有无符号值进一步了解
1.编写过程中用到了short类型(有符号型,值范围含负值).两个正数之和得负. 改为int或unsigned short 均可. 2.注意,short型(-32768,32767)举例:做自加运算, ...
- 下载 编译 Android源代码 和 Android kernel源代码
下载Android源码简要流程 : a. 获取repo文件: curl http://commondatastorage.googleapis.com/git-repo-downloads/repo ...
- 爬取CVPR 2018过程中遇到的坑
爬取 CVPR 2018 过程中遇到的坑 使用语言及模块 语言: Python 3.6.6 模块: re requests lxml bs4 过程 一开始都挺顺利的,先获取到所有文章的链接再逐个爬取获 ...
- WinForm连续点击按钮只打开一次窗体
许多朋友,学习C#时,制作WinForm小程序总会有一个问题,如果我们在父窗体设置的是点击一个按钮,打开一个子窗体,连续点击总会连续出现一样窗体,可是我们有时只想打开一次窗体,怎么办? 呵呵,我来方法 ...
- PAT 甲级 1048 Find Coins
https://pintia.cn/problem-sets/994805342720868352/problems/994805432256675840 Eva loves to collect c ...
- server2003 必要的系统优化和安全设置
修改远程桌面端口: Windows 2003系统中的远程终端服务是一项功能非常强大的服务,同时也成了入侵者长驻主机的通道,入侵者可以利用一些手段得到管理员账号和密码并入侵主机.下面,我们来看看如何通过 ...
- QT分析之QPushButton的初始化
原文地址:http://blog.163.com/net_worm/blog/static/127702419201001003326522/ 在简单的QT程序的第二行,声明了一个QPushButto ...
- Android出现:Your project path contains non-ASCII characters.
导入Project的出现: Error:(1, 0) Your project path contains non-ASCII characters. This will most likely ca ...
- 浅析Docker容器的应用场景
本文来自网易云社区 作者:娄超 过去几年开源界以openstack为代表的云计算持续火了好久,这两年突然又冒出一个叫Docker的容器技术,其发展之迅猛远超预料.网上介绍Docker容器的文章已经很多 ...