传送门

解题思路

  这里写的是常数巨大的线段树套\(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. Jquery append() 添加多次同个元素时,只有一次作用,如何解决?

    这是一个简单的table <table id="mytable"> <!-- 这里将要动态加载tr数据 --> </table> 这是一个模版t ...

  2. 2019/10/26 TZOJ

    1001 Flooded Island http://www.tzcoder.cn/acmhome/problemdetail.do?&method=showdetail&id=452 ...

  3. 02 - Jmeter4.x正则表达式以及跨线程使用变量

    话不多说 直接开撸 上图可以看出,有两个请求,其中第二个请求返回了登录超时,结合第一个登录接口来看,这个是需要header请求内容的也就是 token:当然设置一个token又怎么可能难得倒我们,无非 ...

  4. deepin下安装配置git

    https://blog.csdn.net/menglinjie/article/details/77145537 1.安装gitsudo apt-get install git12.配置用户名和邮箱 ...

  5. bzoj1897. tank 坦克游戏(决策单调性分治)

    题目描述 有这样一款新的坦克游戏.在游戏中,你将操纵一辆坦克,在一个N×M的区域中完成一项任务.在此的区域中,将会有许多可攻击的目标,而你每摧毁这样的一个目标,就将获得与目标价值相等的分数.只有获得了 ...

  6. centos7中mysql不能输入中文问题的解决

    首先在数据库里面输入 mysql> show variables like'%char%' -> ; +--------------------------------------+--- ...

  7. http响应代码解释

    200:成功响应 302:找到,但是请求的资源在另外一个不同的url中. 400:错误请求.这个请求不能被服务器所理解,客户端必须修改请求. 401:未认证,这个请求需要用户认证. 404:未找到.服 ...

  8. C语言如何打印出%

    1. 敲ASCII码,但系我记不住呀! 2. 两个%%: #include <stdio.h> int main() { printf("%%\n"); printf( ...

  9. js的label标签语句与with语句的用法

    /** * label标签语句 * - 语法: * 标签名: 语句 * 如:start: n = 1; * 上面标签start可以被之后的break或continue语句引用 * - label标签语 ...

  10. elasticsearch索引清理脚本shell

    es-index-clear.sh: #!/bin/bash#----------------------------------------------# Module: es-index-clea ...