LUOGU P3380 【模板】二逼平衡树(树套树)
解题思路
这里写的是常数巨大的线段树套\(splay\),卡了半天常才过。首先线段树每个节点挂一个\(splay\),\(splay\)中的元素即为线段树管辖的区间中的数。对于操作\(1\),发现\(rk\)是可以求和的,所以直接在线段树上找到对应区间求\(rk\)即可,时间复杂度\(O(nlog^2n)\);对于操作\(2\),发现不具有可加性,所以要二分转化成求\(rk\),时间复杂度\(O(nlog^3n)\);对于操作\(3\),直接在线段树中找到对应区间,\(splay\)中删数加数即可,时间复杂度\(O(nlog^2n)\);对于操作\(4,5\),直接在对应后继然后取\(min\)取\(max\)即可,时间复杂度\(O(nlog^2n)\)
代码
// luogu-judger-enable-o2
#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=50005;
const int M=N*40;
const int inf=2147483647;
inline int rd(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
}
void out(int x){
if(!x) return; out(x/10); putchar('0'+x%10);
}
inline void OUT(int x) {
if(!x) putchar('0');
else (x>0)?(out(x)):(putchar('-'),out(-x));
putchar('\n');
}
inline int min(int x,int y) {return x<y?x:y;}
inline int max(int x,int y) {return x>y?x:y;}
int n,m,rt,tot=2,zz[N],ans,Max,Min=inf;
struct Splay{
int val[M],ch[M][2],fa[M],siz[M],cnt[M],rt[M];
inline bool check(int x){return (x==ch[fa[x]][1]);}
inline void pushup(int x) {siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];}
inline void rotate(int x){
int y=fa[x],z=fa[y]; bool chk=check(x);
if(z) ch[z][check(y)]=x; ch[y][chk]=ch[x][chk^1];
fa[ch[x][chk^1]]=y; ch[x][chk^1]=y; fa[y]=x; fa[x]=z;
pushup(y); pushup(x);
}
inline void splay(int x,int top,int id){
for(;fa[x]!=top;rotate(x))
if(fa[fa[x]]!=top) rotate(check(fa[x])==check(x)?fa[x]:x);
if(!top) rt[id]=x;
}
inline void find(int x,int y){
int now=rt[y];
while(1){
if(val[now]==x) {splay(now,0,y); return;}
if(x>val[now]) now=ch[now][1];
else now=ch[now][0];
}
}
inline int get_pre(int x){
int now=ch[rt[x]][0]; if(!now) return 2;
while(ch[now][1]) now=ch[now][1];
return now;
}
inline int get_nxt(int x){
int now=ch[rt[x]][1]; if(!now) return 1;
while(ch[now][0]) now=ch[now][0];
return now;
}
inline void insert(int x,int y){
if(!rt[x]) {rt[x]=++tot; val[tot]=y; siz[tot]=cnt[tot]=1; return;}
register int now=rt[x],lst=0;
while(1){
if(val[now]==y) {cnt[now]++; splay(now,0,x); return;}
lst=now; now=ch[now][y>val[now]];
if(!now) {
now=++tot; val[now]=y; cnt[now]=siz[now]=1;
ch[lst][y>val[lst]]=now; fa[now]=lst;
splay(now,0,x); return;
}
}
}
inline void erase(int x,int y){
find(y,x); register int now=rt[x],Pre,Nxt;
if(cnt[now]>1) cnt[now]--;
else if(!ch[now][0] && !ch[now][1]) rt[x]=0;
else if(!ch[now][0]) fa[ch[now][1]]=0,rt[x]=ch[now][1];
else if(!ch[now][1]) fa[ch[now][0]]=0,rt[x]=ch[now][0];
else {
Pre=get_pre(x); Nxt=get_nxt(x);
splay(Pre,0,x); splay(Nxt,Pre,x);
ch[Nxt][0]=0; splay(Nxt,0,x);
}
}
inline int rk(int x,int y){
register int now=rt[x],ret=0;
while(1){
if(!now) return ret;
if(val[now]==y) {ret+=siz[ch[now][0]]; splay(now,0,x); return ret;}
if(val[now]<y) ret+=siz[ch[now][0]]+cnt[now],now=ch[now][1];
else now=ch[now][0];
}
}
}tree2;
struct Segment_Tree{
#define mid ((l+r)>>1)
int ls[M],rs[M];
void update(int x,int l,int r,int pos,int w){
tree2.insert(x,w); if(l==r) return;
if(pos<=mid) update(x<<1,l,mid,pos,w);
else update(x<<1|1,mid+1,r,pos,w);
}
void modify(int x,int l,int r,int pos,int w){
tree2.erase(x,zz[pos]); tree2.insert(x,w);
if(l==r) return;
if(pos<=mid) modify(x<<1,l,mid,pos,w);
else modify(x<<1|1,mid+1,r,pos,w);
}
void query_rk(int x,int l,int r,int L,int R,int k){
// if(L<=l && r<=R) cout<<l<<" "<<r<<" "<<x<<" "<<tree2.rk(x,k)<<endl;
if(L<=l && r<=R) {ans+=tree2.rk(x,k); return; }
if(L<=mid) query_rk(x<<1,l,mid,L,R,k);
if(mid<R) query_rk(x<<1|1,mid+1,r,L,R,k);
}
void query_pre(int x,int l,int r,int L,int R,int k){
if(L<=l && r<=R) {
tree2.insert(x,k);
ans=max(ans,tree2.val[tree2.get_pre(x)]);
tree2.erase(x,k);
return;
}
if(L<=mid) query_pre(x<<1,l,mid,L,R,k);
if(mid<R) query_pre(x<<1|1,mid+1,r,L,R,k);
}
void query_nxt(int x,int l,int r,int L,int R,int k){
if(L<=l && r<=R) {
tree2.insert(x,k);
ans=min(ans,tree2.val[tree2.get_nxt(x)]);
tree2.erase(x,k);
return;
}
if(L<=mid) query_nxt(x<<1,l,mid,L,R,k);
if(mid<R) query_nxt(x<<1|1,mid+1,r,L,R,k);
}
#undef mid
}tree1;
inline int query_kth(int l,int r,int lim){
int L=Min,R=Max,mid,ret;
while(L<=R){
mid=(L+R)>>1; ans=1; tree1.query_rk(1,1,n,l,r,mid);
if(ans>lim) R=mid-1; else ret=mid,L=mid+1;
}
return ret;
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
tree2.val[2]=-inf; tree2.val[1]=inf;
n=rd(),m=rd(); int x,l,r,k,opt,L,R;
for(register int i=1;i<=n;++i)
zz[i]=rd(),tree1.update(1,1,n,i,zz[i]),Max=max(Max,zz[i]),Min=min(Min,zz[i]);
while(m--){
opt=rd();
if(opt==1){
l=rd(),r=rd(),k=rd(); ans=1;
tree1.query_rk(1,1,n,l,r,k);
OUT(ans);
}
else if(opt==2){
l=rd(),r=rd(),k=rd();
OUT(query_kth(l,r,k));
}
else if(opt==3){
x=rd(),k=rd();
tree1.modify(1,1,n,x,k);
zz[x]=k; Max=max(Max,k); Min=min(Min,k);
}
else if(opt==4){
l=rd(),r=rd(),k=rd(); ans=-inf;
tree1.query_pre(1,1,n,l,r,k);
OUT(ans);
}
else if(opt==5){
l=rd(),r=rd(),k=rd(); ans=inf;
tree1.query_nxt(1,1,n,l,r,k);
OUT(ans);
}
}
return 0;
}
LUOGU P3380 【模板】二逼平衡树(树套树)的更多相关文章
- bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1807 Solved: 772[Submit][Stat ...
- bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description ...
- BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)
我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线 ...
- BZOJ3196 二逼平衡树 【线段树套平衡树】
题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱 ...
- BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay
传送门 题意 给你一个长度为 $ n $ 有序数列 $ a $ ,进行 $ m $ 次操作,操作有如下几种: 查询 $ k $ 在区间 $ [l,r] $ 内的排名 查询区间 $ [l,r] $ 内排 ...
- [BZOJ3196] [Tyvj1730] 二逼平衡树(线段树 套 Splay)
传送门 至少BZOJ过了,其他的直接弃. 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的 ...
- bzoj 3196 Tyvj 1730 二逼平衡树【线段树 套 splay】
四舍五入就是个暴力. 对于线段树的每个区间都开一棵按权值排序的splay 对于第二个操作,二分一下,每次查询mid的排名,复杂度 $ O(nlog(n)^{3}) $ 其余的操作都是$ O(nlog( ...
- P3380 【模板】二逼平衡树(树套树)(线段树套平衡树)
P3380 [模板]二逼平衡树(树套树) 前置芝士 P3369 [模板]普通平衡树 线段树套平衡树 这里写的是线段树+splay(不吸氧竟然卡过了) 对线段树的每个节点都维护一颗平衡树 每次把给定区间 ...
- 洛谷P3380 【模板】二逼平衡树(树套树)(线段树+树状数组)
P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...
- 洛谷 P3380 【模板】二逼平衡树(树套树)-线段树套splay
P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...
随机推荐
- Jenkins使用五:创建部署任务
创建部署任务 选择运行节点 选择使用shell # 如果是持续进程,这里最好加一个kill进程的命令 判断如果/root/production目录存在,就删除if [ -d /root/product ...
- 屏幕适配dip
android适配一般使用dpi 那dpi与分辨率,屏幕尺寸的关系 DPI值计算是屏幕对角线的像素值除以屏幕的大小 dip=/ 屏幕尺寸, 比如:计算WVGA(800*480)分辨率,3.7英寸的密度 ...
- PHP 数组函数-数组排序
php数组排序函数sort ( &$arr [,fruits] ) 对数组进行从低到高排序 ,并赋予新的键名 返回boolrsort ( &$arr [,fruits] ) 对数组进行 ...
- 网易新闻实战 --- flask,ORM, Ajax异步删除
项目概述: 包含功能: 前端-- 新闻首页 新闻分类页 新闻详情页 后端-- 后台新闻管理(列表,分页) 新增新闻 修改新闻 删除新闻(AJAX)
- 题解[SCOI2009]粉刷匠 难度:省选/NOI-
Description windy有 N 条木板需要被粉刷.每条木板被分为 M 个格子.每个格子要被刷成红色或蓝色.windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色.每个格子最多 ...
- TensorFlow学习笔记2-性能分析工具
TensorFlow学习笔记2-性能分析工具 性能分析工具 在spyder中运行以下代码: import tensorflow as tf from tensorflow.python.client ...
- jQury+Ajax与C#后台交换数据
-------------------------------------------jQury+Ajax调用后台方法----------------------------------------- ...
- mybatis多对多
这里我们以用户 user 表和 角色role 表为例,假定一个用户能被分配成多重角色,而一种角色也能分给多个用户,故用户和角色构成多对多的关系 需求:给定角色id,查询这个角色所属的所有用户信息 ①. ...
- maven配置本地仓库、maven配置阿里中央仓库、eclipse配置maven
一.maven配置本地仓库路径 1.打开下载好的maven目录 (若没安装,可以看我写的安装步骤https://www.cnblogs.com/xjd-6/p/11344719.html) 2.进入c ...
- 解决Maven项目BindingException异常
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.offcn.mybatis.m ...