树套树
树套树
线段树套平衡树
在平衡树操作的基础上加上区间的限制,就需要用树套树了
线段树套平衡树就是线段树的每一个节点都是一棵平衡树
线段树管理区间,平衡树维护区间中数的信息
平衡树用的常数较小的\(treap\),粘的,就不讲了,下面是线段树部分
建树
建线段树的时候把对应的数加入平衡树
il void build(int rt,int l,int r) {
for(ri int i=l;i<=r;++i) treap::ins(rot[rt],p[i]);
if(l^r){
ri int mid=(l+r)>>1;
build(ls(rt),l,mid);
build(rs(rt),mid+1,r);
}
}
查询区间排名
在线段树上找到对应区间,每个节点的平衡树内查询对应数的排名并求和,复杂度 \(O(\log^2 n)\)
il int rnk(int rt,int l,int r,int ql,int qr,int k) {
if(ql<=l&&r<=qr) return treap::rnk(rot[rt],k);
ri int as=0,mid=(l+r)>>1;
if(mid>=ql) as+=rnk(ls(rt),l,mid,ql,qr,k);
if(mid<qr) as+=rnk(rs(rt),mid+1,r,ql,qr,k);
return as;
}
查询区间第 \(k\) 小
\(\log n\) 二分答案,\(\log^2 n\) 检查 \(mid\) 的排名是否为 \(k\),复杂度 \(O(\log^3 n)\)
il int kth(int ql,int qr,int k) {
ri int l=0,r=1e8,mid;
while(l<r) {
mid=(l+r+1)>>1; //
if(rnk(1,1,n,ql,qr,mid)<k) l=mid;
else r=mid-1;
}
return r;
}
单点修改
在线段树上找到所有包含该点的区间,在所有区间对应的平衡树中删除原数,加入新数,复杂度 \(O(\log^2 n)\)
il void upd(int rt,int l,int r,int pos,int k) {
treap::del(rot[rt],p[pos]);
treap::ins(rot[rt],k);
if(l^r) {
ri int mid=(l+r)>>1;
if(pos <= mid) upd(ls(rt),l,mid,pos,k);
else upd(rs(rt),mid+1,r,pos,k);
}
}
查询区间前驱
对所有区间分别查询,答案取 \(max\),复杂度 \(O(\log^2 n)\)
il int pre(int rt,int l,int r,int ql,int qr,int k) {
if(ql<=l&&r<=qr) return treap::pre(rot[rt],k);
ri int as=-inf, mid=(l+r)>>1;
if(mid>=ql) as=max(as,pre(ls(rt),l,mid,ql,qr,k));
if(mid<qr) as=max(as,pre(rs(rt),mid+1,r,ql,qr,k));
return as;
}
查询区间后继
对所有区间分别查询,答案取 \(min\),复杂度 \(O(\log^2 n)\)
il int nxt(int rt, int l, int r, int ql, int qr, int k) {
if(ql<=l&&r<=qr) return treap::nxt(rot[rt],k);
ri int as=inf,mid=(l+r)>>1;
if(mid>=ql) as=min(as,nxt(ls(rt),l,mid,ql,qr,k));
if(mid<qr) as=min(as,nxt(rs(rt),mid+1,r,ql,qr,k));
return as;
}
code
//不开o2可过qwq
#include <bits/stdc++.h>
#define il inline
#define cs const
#define ri register
#define F(s) freopen(#s".in","r",stdin),freopen(#s".out","w",stdout);
using namespace std;
namespace Q{
il int rd(){
ri int x=0;ri bool f=0;ri char c=getchar();
while(!isdigit(c)) f|=(c==45),c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar(45);
if(x>=10) wt(x/10);
return putchar(x%10|48),void();
}
} using namespace Q;
cs int N=5e4+5,inf=2147483647;
int p[N],n,m;
namespace treap{
int id;
mt19937 srd(314);
struct tree{int s[2],vl,dt,ct,sz;} t[N*40];
il void upd(cs int &i){
t[i].sz=t[i].ct+t[t[i].s[0]].sz+t[t[i].s[1]].sz;
return;
}
il void rtt(int &i,cs bool d){//1zig 0zag
int o=t[i].s[d^1];
t[i].s[d^1]=t[o].s[d];
t[o].s[d]=i,t[o].sz=t[i].sz;
return upd(i),i=o,void();
}
il int add(cs int &x){
t[++id].vl=x,t[id].dt=srd(),t[id].sz=t[id].ct=1;
t[id].s[0]=t[id].s[1]=0;return id;
}
il void ins(int &i,cs int &x){
if(!i) return i=add(x),void();
else t[i].sz++;
if(t[i].vl==x) t[i].ct++;
else{
bool d=(t[i].vl<x);
ins(t[i].s[d],x);
if(t[t[i].s[d]].dt<t[i].dt) rtt(i,d^1);
}
return;
}
il void del(int &i,cs int &x){
if(t[i].vl==x){
if(t[i].ct>1) t[i].ct--,t[i].sz--;
else if(!(t[i].s[0]*t[i].s[1])) i=t[i].s[0]+t[i].s[1];
else{
bool d=(t[t[i].s[0]].dt<t[t[i].s[1]].dt);
rtt(i,d),del(i,x);
}
return;
}
return t[i].sz--,del(t[i].s[(x>t[i].vl)],x);
}
il int rnk(int rt,cs int &x){
ri int i=rt,rk=0;//
while(i){
if(x==t[i].vl) return rk+t[t[i].s[0]].sz;
if(x<t[i].vl) i=t[i].s[0];
else rk+=t[t[i].s[0]].sz+t[i].ct,i=t[i].s[1];
}
return rk;
}
il int kth(int rt,int x){
ri int i=rt;
while(i){
if(t[t[i].s[0]].sz<x&&t[t[i].s[0]].sz+t[i].ct>=x) return t[i].vl;
if(t[t[i].s[0]].sz>=x) i=t[i].s[0];
else x-=t[t[i].s[0]].sz+t[i].ct,i=t[i].s[1];
}
return 0;
}
il int pre(int rt,cs int &x){
ri int i=rt,as=-inf;
while(i){
if(t[i].vl<x) as=t[i].vl,i=t[i].s[1];
else i=t[i].s[0];
}
return as;
}
il int nxt(int rt,cs int &x){
ri int i=rt,as=inf;
while(i){
if(t[i].vl>x) as=t[i].vl,i=t[i].s[0];
else i=t[i].s[1];
}
return as;
}
}
namespace xds {
#define ls(rt) (rt<<1)
#define rs(rt) (rt<<1|1)
int rot[N<<4];
il void build(int rt,int l,int r) {
for(ri int i=l;i<=r;++i) treap::ins(rot[rt],p[i]);
if(l^r){
ri int mid=(l+r)>>1;
build(ls(rt),l,mid);
build(rs(rt),mid+1,r);
}
}
il void upd(int rt,int l,int r,int pos,int k) {
treap::del(rot[rt],p[pos]);
treap::ins(rot[rt],k);
if(l^r) {
ri int mid=(l+r)>>1;
if(pos <= mid) upd(ls(rt),l,mid,pos,k);
else upd(rs(rt),mid+1,r,pos,k);
}
}
il int rnk(int rt,int l,int r,int ql,int qr,int k) {
if(ql<=l&&r<=qr) return treap::rnk(rot[rt],k);
ri int as=0,mid=(l+r)>>1;
if(mid>=ql) as+=rnk(ls(rt),l,mid,ql,qr,k);
if(mid<qr) as+=rnk(rs(rt),mid+1,r,ql,qr,k);
return as;
}
il int kth(int ql,int qr,int k) {
ri int l=0,r=1e8,mid;
while(l<r) {
mid=(l+r+1)>>1; //
if(rnk(1,1,n,ql,qr,mid)<k) l=mid;
else r=mid-1;
}
return r;
}
il int pre(int rt,int l,int r,int ql,int qr,int k) {
if(ql<=l&&r<=qr) return treap::pre(rot[rt],k);
ri int as=-inf, mid=(l+r)>>1;
if(mid>=ql) as=max(as,pre(ls(rt),l,mid,ql,qr,k));
if(mid<qr) as=max(as,pre(rs(rt),mid+1,r,ql,qr,k));
return as;
}
il int nxt(int rt, int l, int r, int ql, int qr, int k) {
if(ql<=l&&r<=qr) return treap::nxt(rot[rt],k);
ri int as=inf,mid=(l+r)>>1;
if(mid>=ql) as=min(as,nxt(ls(rt),l,mid,ql,qr,k));
if(mid<qr) as=min(as,nxt(rs(rt),mid+1,r,ql,qr,k));
return as;
}
#undef ls
#undef rs
}
signed main() {
n=rd(),m=rd();
for(ri int i=1;i<=n;++i) p[i]=rd();
xds::build(1,1,n);
for(ri int i=1,op,l,r,k;i<=m;++i) {
op=rd();
switch (op){
case 1:
l=rd(),r=rd(),k=rd();
wt(xds::rnk(1,1,n,l,r,k)+1);
putchar(10);
break;
case 2:
l=rd(),r=rd(),k=rd();
wt(xds::kth(l,r,k));
putchar(10);
break;
case 3:
l=rd(),k=rd();
xds::upd(1,1,n,l,k);
p[l]=k;
break;
case 4:
l=rd(),r=rd(),k=rd();
wt(xds::pre(1,1,n,l,r,k));
putchar(10);
break;
default:
l=rd(),r=rd(),k=rd();
wt(xds::nxt(1,1,n,l,r,k));
putchar(10);
break;
}
}
return 0;
}
I went to the woods because I wanted to live deliberately, I wanted to live deep and suck out all the marrow of life, and not when I had come to die, discover that I had not live.