传送门

解题思路

  这里写的是常数巨大的线段树套\(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 【模板】二逼平衡树(树套树)的更多相关文章

  1. bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1807  Solved: 772[Submit][Stat ...

  2. bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description ...

  3. BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)

    我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线 ...

  4. BZOJ3196 二逼平衡树 【线段树套平衡树】

    题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱 ...

  5. BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay

    传送门 题意 给你一个长度为 $ n $ 有序数列 $ a $ ,进行 $ m $ 次操作,操作有如下几种: 查询 $ k $ 在区间 $ [l,r] $ 内的排名 查询区间 $ [l,r] $ 内排 ...

  6. [BZOJ3196] [Tyvj1730] 二逼平衡树(线段树 套 Splay)

    传送门 至少BZOJ过了,其他的直接弃. 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的 ...

  7. bzoj 3196 Tyvj 1730 二逼平衡树【线段树 套 splay】

    四舍五入就是个暴力. 对于线段树的每个区间都开一棵按权值排序的splay 对于第二个操作,二分一下,每次查询mid的排名,复杂度 $ O(nlog(n)^{3}) $ 其余的操作都是$ O(nlog( ...

  8. P3380 【模板】二逼平衡树(树套树)(线段树套平衡树)

    P3380 [模板]二逼平衡树(树套树) 前置芝士 P3369 [模板]普通平衡树 线段树套平衡树 这里写的是线段树+splay(不吸氧竟然卡过了) 对线段树的每个节点都维护一颗平衡树 每次把给定区间 ...

  9. 洛谷P3380 【模板】二逼平衡树(树套树)(线段树+树状数组)

    P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...

  10. 洛谷 P3380 【模板】二逼平衡树(树套树)-线段树套splay

    P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...

随机推荐

  1. HTML--JS 表单验证

    <html> <head> <title>验证表单</title> <script type="text/javascript" ...

  2. Visual Studio中把文件夹导入工程中

    VS用到的功能还是太少,记录备忘. 有的时候需要把其他库的源码导入当前工程直接使用,而这个库是源码形式,又带很多目录的. 之前从没遇到过这种情况,自己的库目录自己新建,添加. 第三方库一般有单独的Pr ...

  3. 普通ACL访问控制列表

    配置OSPF R1: R2: R3: R4: 在R1上查看OSPF的学习 测试R1与R4环回接口连通性 配置普通ACL访问控制列表: 先在R4配置密码用R1与R4建立telnet建立 密码huawei ...

  4. servlet--禁用浏览器缓存

    禁用浏览器缓存:Cache-Control.pragma.expires response.setHeader("Cache-Control", "no-cache&qu ...

  5. eclipse配置,快捷键备忘

    1. General --> Workspace --> UTF-82. General --> Editors --> Associations --> JSP --& ...

  6. 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 ...

  7. python中bytes和str

    1.python中bytes和str Python3 最重要的新特性大概要算是对文本(text)和二进制数据(binary data)作了更为清晰的区分 (1)Python 3.0使用文本和(二进制) ...

  8. Topcoder SRM652div2

    开始接触Topcode..div2.. 250题目: Problem Statement      You are given a String s consisting of lower to , ...

  9. CodeChef Sereja and GCD

    Sereja and GCD   Problem code: SEAGCD   Submit All Submissions   All submissions for this problem ar ...

  10. linux性能分析工具Sysstat