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的值 修改某一位值上的数 ...
随机推荐
- HTML--JS 表单验证
<html> <head> <title>验证表单</title> <script type="text/javascript" ...
- Visual Studio中把文件夹导入工程中
VS用到的功能还是太少,记录备忘. 有的时候需要把其他库的源码导入当前工程直接使用,而这个库是源码形式,又带很多目录的. 之前从没遇到过这种情况,自己的库目录自己新建,添加. 第三方库一般有单独的Pr ...
- 普通ACL访问控制列表
配置OSPF R1: R2: R3: R4: 在R1上查看OSPF的学习 测试R1与R4环回接口连通性 配置普通ACL访问控制列表: 先在R4配置密码用R1与R4建立telnet建立 密码huawei ...
- servlet--禁用浏览器缓存
禁用浏览器缓存:Cache-Control.pragma.expires response.setHeader("Cache-Control", "no-cache&qu ...
- eclipse配置,快捷键备忘
1. General --> Workspace --> UTF-82. General --> Editors --> Associations --> JSP --& ...
- Meet in the middle算法总结 (附模板及SPOJ ABCDEF、BZOJ4800、POJ 1186、BZOJ 2679 题解)
目录 Meet in the Middle 总结 1.算法模型 1.1 Meet in the Middle算法的适用范围 1.2Meet in the Middle的基本思想 1.3Meet in ...
- python中bytes和str
1.python中bytes和str Python3 最重要的新特性大概要算是对文本(text)和二进制数据(binary data)作了更为清晰的区分 (1)Python 3.0使用文本和(二进制) ...
- Topcoder SRM652div2
开始接触Topcode..div2.. 250题目: Problem Statement You are given a String s consisting of lower to , ...
- CodeChef Sereja and GCD
Sereja and GCD Problem code: SEAGCD Submit All Submissions All submissions for this problem ar ...
- linux性能分析工具Sysstat