【TYVJ1730】【洛谷P3380】—二逼平衡树(树套树)
发现树套树也不是很难嘛
当然很难调
然而开始我连树套树怎么写都不知道
手动了两发
了之后找了份标程对拍,拍了之后又调
弄了大半天终于搞定了
自己写的是外层线段树套内层-
对于线段树每一个区间节点,将区间建成一个
然后线段树将询问区间分成个区间
每个在上统计答案
复杂度
具体细节看代码
洛谷上开莫名
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=5000005;
const int inf=2147483647;
int n,m,a[N],mx;
namespace FHQ_Treap{
int son[N][2],siz[N],val[N],key[N],tot;
#define lc(u) son[u][0]
#define rc(u) son[u][1]
void write(int u){//调试语句,按从小到大遍历一个Treap
if(son[u][0])write(son[u][0]);
cout<<val[u]<<" ";
if(son[u][1])write(son[u][1]);
}
inline int addnode(int k){
int u=++tot;
val[tot]=k,key[tot]=rand();
siz[tot]=1;return tot;
}
inline void pushup(int u){
siz[u]=siz[lc(u)]+siz[rc(u)]+1;
}
void merge(int &u,int r1,int r2){
if(!r1||!r2){u=r1+r2;return;}
if(key[r1]<key[r2])u=r1,merge(rc(u),rc(r1),r2);
else u=r2,merge(lc(u),r1,lc(r2));
pushup(u);
}
void split(int u,int &r1,int &r2,int v){
if(u==0){r1=r2=0;return;}
if(val[u]<=v){
r1=u,split(rc(u),rc(r1),r2,v);
}
else r2=u,split(lc(u),r1,lc(r2),v);
pushup(u);
}
inline int getrk(int rt,int k){
int r1,r2;
split(rt,r1,r2,k-1);
int res=siz[r1];
merge(rt,r1,r2);
return res;
}
inline int insert(int &rt,int v){
int u=addnode(v),r1,r2;
split(rt,r1,r2,v);
merge(r1,r1,u);
merge(rt,r1,r2);
}
inline int delet(int &rt,int v){
int r1,r2,r3;
split(rt,r1,r2,v);
split(r1,r1,r3,v-1);
merge(r3,lc(r3),rc(r3));
merge(r1,r1,r3);
merge(rt,r1,r2);
}
inline int pre(int rt,int v){
int r1,r2;
split(rt,r1,r2,v-1);
if(!r1)return -inf;
int u=r1;
while(rc(u))u=rc(u);
merge(rt,r1,r2);
return val[u];
}
inline int nxt(int rt,int v){
int r1,r2;
split(rt,r1,r2,v);
if(!r2)return inf;
int u=r2;
while(lc(u))u=lc(u);
merge(rt,r1,r2);
return val[u];
}
#undef lc
#undef rc
}
using namespace FHQ_Treap;
namespace Seg{
int rt[N];
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
void buildtree(int u,int l,int r){
for(int i=l;i<=r;++i)insert(rt[u],a[i]);
if(l==r)return;
buildtree(lc,l,mid);
buildtree(rc,mid+1,r);
}
int queryrk(int u,int l,int r,int st,int des,int k){
if(st<=l&&r<=des)return getrk(rt[u],k);
int res=0;
if(st<=mid)res+=queryrk(lc,l,mid,st,des,k);
if(mid<des)res+=queryrk(rc,mid+1,r,st,des,k);
return res;
}
void update(int u,int l,int r,int pos,int k){
delet(rt[u],a[pos]),insert(rt[u],k);
if(l==r)return;
if(pos<=mid)update(lc,l,mid,pos,k);
else update(rc,mid+1,r,pos,k);
}
int querypre(int u,int l,int r,int st,int des,int k){
if(st<=l&&r<=des)return pre(rt[u],k);
int res=-inf;
if(st<=mid)res=max(res,querypre(lc,l,mid,st,des,k));
if(mid<des)res=max(res,querypre(rc,mid+1,r,st,des,k));
return res;
}
int querynxt(int u,int l,int r,int st,int des,int k){
if(st<=l&&r<=des)return nxt(rt[u],k);
int res=inf;
if(st<=mid)res=min(res,querynxt(lc,l,mid,st,des,k));
if(mid<des)res=min(res,querynxt(rc,mid+1,r,st,des,k));
return res;
}
}
using namespace Seg;
inline int kth(int st,int des,int k){
int ans=0,l=0,r=mx+1;
while(l<r){
int pk=queryrk(1,1,n,st,des,mid);
if(pk<k)l=mid+1;
else r=mid;
}
return l-1;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read(),mx=max(mx,a[i]);
buildtree(1,1,n);
for(int i=1;i<=m;i++){
int op=read();
switch(op){
case 1:{
int l=read(),r=read(),k=read();
cout<<queryrk(1,1,n,l,r,k)+1<<'\n';
break;
}
case 2:{
int l=read(),r=read(),k=read();
cout<<kth(l,r,k)<<'\n';
break;
}
case 3:{
int pos=read(),k=read();
update(1,1,n,pos,k);a[pos]=k;
break;
}
case 4:{
int l=read(),r=read(),k=read();
cout<<querypre(1,1,n,l,r,k)<<'\n';
break;
}
case 5:{
int l=read(),r=read(),k=read();
cout<<querynxt(1,1,n,l,r,k)<<'\n';
break;
}
}
}
}