[BZOJ3196] 二逼平衡树 [权值线段树套位置平衡树]
题面
思路
没错我就是要不走寻常路!
看看那些外层位置数据结构,必须二分的,$O(n\log^3 n)$的做法吧!
看看那些cdq分治/树状数组套线段树的,空间$O(n\log^2 n)$挤挤挤开不下的做法吧!
这些都不是最优秀的,我来写一种理论复杂度为时间$O(n\log n\log (m+n))$,空间$O(n\log (n+m))$的做法
我们首先考虑时间问题:为什么传统做法的复杂度是3个$log$的?
核心问题是他们有一个二分,否则无法处理第二种询问
那么可以看到第二种询问本质上就是关于区间中权值从小到大排序以后提取出某一位作为答案
考虑把内外层数据结构的意义交换:外层维护权值,内层维护位置
对于询问一:
这里就是简单查询,在外层数对应的区间范围内查询一共有多少个内层数上位于询问区间内的点即可
实现函数为$getk$
对于询问二:
首先,答案就是这个区间内排名为第$k$的数的权值
我们在外层树上二分查找,每次询问内层中外层当前节点的左儿子询问区间中节点个数
如果左边比需要的大就递归进入左边,否则需要的值先减去左边的总数,再进入右边
最后返回叶节点的权值
代码实现为$query$函数
对于修改三
删除再插入即可
对于询问四
我们首先查询,在给定区间内,比询问的数小的数有多少个(用$getk$函数)
然后,其实这个数量,等价于排名
所以我们把排名+1,再用$query$函数输出这个排名对应的数
对于询问五,基本与询问4等价,不赘述
综上,这里的核心思路其实就是:
比某个数小的数字的个数就是这个数的排名
实现的时候,注意外层和内层不同于常规树套树
使用指针or引用可以得到比较好的效果
同时,如果不离散化,时间复杂度和空间复杂度里面的那个$\log(n+m)$都会变成$\log 10^8$
不过也是可以过的
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<queue>
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
namespace spl{
int ch[6000010][2],w[6000010],siz[6000010],fa[6000010],cnt;
void update(int cur){
siz[cur]=siz[ch[cur][0]]+siz[ch[cur][1]]+1;
}
int newnode(int f,int val){
cnt++;
fa[cnt]=f;siz[cnt]=1;ch[cnt][0]=ch[cnt][1]=0;w[cnt]=val;
return cnt;
}
bool get(int cur){return ch[fa[cur]][1]==cur;}
void rotate(int x){
int f=fa[x],ff=fa[f],son=get(x);
ch[f][son]=ch[x][son^1];
if(ch[f][son]) fa[ch[f][son]]=f;
fa[f]=x;ch[x][son^1]=f;
fa[x]=ff;
if(ff) ch[ff][ch[ff][1]==f]=x;
update(f);update(x);
}
void splay(int x,int to,int &root){
for(int f;(f=fa[x])!=to;rotate(x)){
if(fa[f]!=to)
rotate((get(x)==get(f))?f:x);
}
if(!to) root=x;
}
void insert(int &cur,int val,int f,int &root){
if(!cur){
cur=newnode(f,val);
splay(cur,0,root);
return;
}
siz[cur]++;
if(w[cur]>=val) insert(ch[cur][0],val,cur,root);
else insert(ch[cur][1],val,cur,root);
}
int getpos(int cur,int val){
if(w[cur]==val) return cur;
if(w[cur]>val) return getpos(ch[cur][0],val);
else return getpos(ch[cur][1],val);
}
int pre(int root){
int u=ch[root][0];
while(ch[u][1]) u=ch[u][1];
return u;
}
void del(int val,int &root){
int cur=getpos(root,val);splay(cur,0,root);
if(!ch[cur][0]&&!ch[cur][1]){root=0;return;}
if(!ch[cur][0]&&ch[cur][1]){
fa[ch[cur][1]]=0;root=ch[cur][1];
siz[cur]=ch[cur][0]=ch[cur][1]=fa[cur]=0;
return;
}
if(ch[cur][0]&&!ch[cur][1]){
fa[ch[cur][0]]=0;root=ch[cur][0];
siz[cur]=ch[cur][0]=ch[cur][1]=fa[cur]=0;
return;
}
int p=pre(cur),suf=ch[cur][1];
splay(p,0,root);
assert(fa[cur]==p);
assert(ch[cur][0]==0);
ch[p][1]=suf;fa[suf]=p;update(p);
siz[cur]=ch[cur][0]=ch[cur][1]=fa[cur]=0;
}
int pre(int val,int &root){
int u=root,re=0,minn=1e9;
while(u){
if(w[u]>=val) u=ch[u][0];
else{
if(val-w[u]<minn){minn=val-w[u];re=u;}
u=ch[u][1];
}
}
splay(re,0,root);
return re;
}
int suf(int val,int &root){
int u=root,re=0,minn=1e9;
while(u){
if(w[u]<=val) u=ch[u][1];
else{
if(w[u]-val<minn){minn=w[u]-val;re=u;}
u=ch[u][0];
}
}
splay(re,0,root);
return re;
}
int query(int &root,int l,int r){
int x=pre(l,root),y=suf(r,root);
splay(x,0,root);splay(y,x,root);
return siz[ch[y][0]];
}
}
namespace ct{
int cnt,re;queue<int>q;
int newnode(){
if(!q.empty()){re=q.front();q.pop();return re;}
else return ++cnt;
}
void del(int num){
q.push(num);
}
}
namespace seg{
int root[1000010],ch[1000010][2];
void insert(int &cur,int l,int r,int pos,int val){//pos is value in original list, val is position
if(!cur){
cur=ct::newnode();
spl::insert(root[cur],-1e6,0,root[cur]);
spl::insert(root[cur],1e6,0,root[cur]);
}
spl::insert(root[cur],val,0,root[cur]);
if(l==r) return;
int mid=(l+r)>>1;
if(mid>=pos) insert(ch[cur][0],l,mid,pos,val);
else insert(ch[cur][1],mid+1,r,pos,val);
}
void del(int &cur,int l,int r,int pos,int val){
spl::del(val,root[cur]);
if(l^r){
int mid=(l+r)>>1;
if(mid>=pos) del(ch[cur][0],l,mid,pos,val);
else del(ch[cur][1],mid+1,r,pos,val);
}
if(spl::siz[root[cur]]==2){
ct::del(cur);
spl::del(-1e6,root[cur]);
spl::del(1e6,root[cur]);
ch[cur][0]=ch[cur][1]=root[cur]=0;
cur=0;
}
}
int getk(int &cur,int l,int r,int qx,int qy,int ql,int qr){
if(!cur) return 0;
if(l>=ql&&r<=qr) return spl::query(root[cur],qx,qy);
int mid=(l+r)>>1,re=0;
if(mid>=ql) re+=getk(ch[cur][0],l,mid,qx,qy,ql,qr);
if(mid<qr) re+=getk(ch[cur][1],mid+1,r,qx,qy,ql,qr);
return re;
}
int query(int cur,int l,int r,int pos,int qx,int qy){
if(l==r) return l;
int tmp=0;
if(ch[cur][0]) tmp=spl::query(root[ch[cur][0]],qx,qy);
int mid=(l+r)>>1;
if(tmp>=pos) return query(ch[cur][0],l,mid,pos,qx,qy);
else return query(ch[cur][1],mid+1,r,pos-tmp,qx,qy);
}
}
int a[50010],n,m,rt=0;
int main(){
using namespace seg;
n=read();m=read();
int i,t1,t2,t3,t4,tmp;
for(i=1;i<=n;i++){
a[i]=read();
insert(rt,0,1e8,a[i],i);
}
while(m--){
t1=read();
if(t1==1){
t2=read();t3=read();t4=read();
if(t4==0) puts("1");
else printf("%d\n",getk(rt,0,1e8,t2,t3,0,t4-1)+1);
}
if(t1==2){
t2=read();t3=read();t4=read();
printf("%d\n",query(rt,0,1e8,t4,t2,t3));
}
if(t1==3){
t2=read();t3=read();
del(rt,0,1e8,a[t2],t2);
insert(rt,0,1e8,a[t2]=t3,t2);
}
if(t1==4){
t2=read();t3=read();t4=read();
tmp=getk(rt,0,1e8,t2,t3,0,t4-1);
if(tmp==0) puts("-2147483647");
else printf("%d\n",query(rt,0,1e8,tmp,t2,t3));
}
if(t1==5){
t2=read();t3=read();t4=read();
tmp=getk(rt,0,1e8,t2,t3,0,t4);
if(tmp==t3-t2+1) puts("2147483647");
else printf("%d\n",query(rt,0,1e8,tmp+1,t2,t3));
}
}
}
[BZOJ3196] 二逼平衡树 [权值线段树套位置平衡树]的更多相关文章
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- 【bzoj4605】崂山白花蛇草水 权值线段树套KD-tree
题目描述 神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇Aleph的实力,他轻松地进了山东省省队,现在便是他履行诺言的时候了.蒟蒻Bob ...
- bzoj4605: 崂山白花蛇草水 权值线段树套KDtree
bzoj4605: 崂山白花蛇草水 链接 bzoj loj 思路 强制在线,那就权值线段树套KDtree好了,没啥好讲的. KDtree要加平衡因子来重构.另外,那水真难喝. 错误 树套树一边写过了, ...
- [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)
[BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...
- cogs 1829. [Tyvj 1728]普通平衡树 权值线段树
1829. [Tyvj 1728]普通平衡树 ★★★ 输入文件:phs.in 输出文件:phs.out 简单对比时间限制:1 s 内存限制:1000 MB [题目描述] 您需要写一种数 ...
- [BZOJ3600] 没有人的算术 [重量平衡树+权值线段树]
题面 传送门 思路 这道题目是陈立杰论文<重量平衡树和后缀平衡树在信息学奥赛中的应用 >中关于重量平衡树维护序列排名算法的一个应用 具体方法为:令根节点保存一个实数区间$[0,1]$ 若当 ...
- BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- 崂山白花蛇草水 权值线段树套KDtree
Description 神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇Aleph的实 力,他轻松地进了山东省省队,现在便是他履行诺言的时 ...
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...
随机推荐
- ES6初识-Proxy和Reflect
{ let obj={ time:'2017-03-11', name:'net', _r:123 }; let monitor=new Proxy(obj,{ // 拦截对象属性的读取 get( ...
- Thinkphp 取消Url默认模块的现实
例子http://www.tp.com/home/index/index 想要现实的效果是:http://www.tp.com/index/index 1是通过配置路由来达到目的 2通过配置首页的入口 ...
- JAVA实现RSA加密,非对称加密算法
RSA.java package org.icesnow.jeasywx.util.security; import java.security.Key; import java.security.K ...
- 连接mysql 报错 Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
网上找不到 朋友说是因为非正常关机导致,mysql.server start 运行报错 ERROR! The server quit without updating PID file(): 解决办 ...
- 【Effective C++ 读书笔记】条款03: 尽量使用 const
关键字const多才多艺,变化多端却不高深莫测. const 修饰指针 面对指针, 你可以指出 指针自身.指针所指物.或者两者都不是 const. 如果关键字 const 出现在星号左边,表示被指物是 ...
- 【转载】char*,const char*和string 三者转换
本文转自 http://blog.csdn.net/perfumekristy/article/details/7027678 const char* 和string 转换 const char*转换 ...
- 小程序里面使用wxParse解析富文本导致页面空白等
在部分安卓手机上会出现白屏的情况且有些ios手机上图文混排上,图片显示不出问题 解决:把插件里面的console.dir去掉即可(原因在于安卓手机无法解析console.dir) 有些图片解析出来下面 ...
- [CodeForces948B]Primal Sport(数论)
Description 题目链接 Solution 设f(x)为x的最大质因子 那么由题意易得\(X_1\)的范围在\([X_2-f(X_2)+1,X2]\) 同理\(X_0\)的范围在\([X_1- ...
- CentOS网络设置 couldn't resolve host 'mirrorlist.centos.org问题解决
在VMWare上安装好centos后,使用yum安装nodejs报错:can not resolve host 'mirritlist.centos.org', 百度上很多都说在/etc/resolv ...
- 笔记-pyton内置数据类型
笔记-pyton内置数据类型 1. 简介 The principal built-in types are numerics, sequences, mappings, classes, i ...